
本文详解如何在 Laravel 中通过 Blade 模板的 <select> 下拉框提交年份参数,并在控制器中正确接收、过滤并展示对应年份的文章数据,涵盖路由配置、表单提交方式、请求参数获取及常见错误规避。
本文详解如何在 laravel 中通过 blade 模板的 `
在 Laravel 构建公告栏(Bulletin Board)类应用时,常需按年份动态筛选文章(如仅显示 2022 年发布的资讯)。但初学者易陷入「表单未提交」「请求参数为空」「路由不支持 POST」等典型问题。以下为经过验证的完整、可运行方案。
✅ 正确实现步骤
1. 路由定义:同时支持 GET(首次加载)和 POST(筛选提交)
// routes/web.php
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::post('/', [HomeController::class, 'index']);⚠️ 注意:必须显式注册 POST 路由,否则表单提交将返回 405 Method Not Allowed。
2. Blade 视图:使用标准 <form> 包裹 <select>,并添加提交按钮
<!-- resources/views/home.blade.php -->
<form method="POST" action="{{ route('home') }}">
@csrf <!-- 必须!防止 Laravel CSRF 验证失败 -->
<select name="article_year">
@foreach($year as $item)
<option value="{{ $item->name }}" {{ request('article_year') == $item->name ? 'selected' : '' }}>
{{ $item->name }}
</option>
@endforeach
</select>
<button type="submit">筛选年份</button>
</form>
<!-- 展示结果 -->
<div class="news-list">
<h3>置顶文章({{ request('article_year') ?? '全部年份' }})</h3>
@foreach($news_pin as $item)
<div>{{ $item->title }} ({{ $item->user_year }})</div>
@endforeach
</div>✅ 关键点:
- 使用 method="POST" 显式声明;
- 添加 @csrf 指令(Laravel 5.7+ 强制要求);
- 利用 request('article_year') 实现选项回显,提升用户体验。
3. 控制器:正确注入 Request,安全获取参数并构建查询
// app/Http/Controllers/HomeController.php
<?php
namespace App\Http\Controllers;
use App\Article;
use App\Catalog;
use Illuminate\Http\Request; // ✅ 正确引入 Request 类
use App\Http\Controllers\Controller;
class HomeController extends Controller
{
public function index(Request $request) // ✅ 正确类型提示与依赖注入
{
// 获取用户选择的年份,若未提交则设为 null(避免全表误筛)
$selectedYear = $request->input('article_year');
// 查询所有可用年份(用于下拉菜单)
$years = Catalog::where('catalog_type_id', 3)
->where('is_active', 1)
->orderBy('sort_num', 'asc')
->get();
// 构建文章查询:注意空值处理 —— 若未选年份,应展示全部(或跳过 where 条件)
$baseQuery = Article::orderBy('sort_num', 'desc');
if ($selectedYear !== null) {
$baseQuery->where('user_year', $selectedYear);
}
$newsPin = $baseQuery->where('is_active', 1)->get();
$news = $baseQuery->where('is_active', 0)->get();
return view('home', [
'year' => $years,
'news_pin' => $newsPin,
'news' => $news,
]);
}
}✅ 关键优化:
- 使用 Request $request 依赖注入(而非过时的 Request::segment() 或全局 request() 辅助函数),更符合 Laravel 最佳实践;
- 用 $request->input() 安全取值(自动处理缺失键,返回 null);
- 对 $selectedYear 做空值判断,避免 where('user_year', null) 导致无结果(应跳过该条件);
- 使用模型门面(Article::)替代 (new Article()),更简洁、支持链式调用与查询缓存。
⚠️ 常见错误与修复对照表
| 错误现象 | 根本原因 | 解决方案 |
|---|---|---|
| 表单提交后页面空白或 405 错误 | 缺少 POST 路由定义 | 补充 Route::post('/', [...]) |
| Undefined variable: request | 控制器方法未声明 Request $request 参数 | 在 index() 方法签名中注入 Request |
| 下拉框选中后刷新丢失状态 | 未在 <option> 中设置 selected 属性 | 使用 {{ request('article_year') == $item->name ? 'selected' : '' }} |
| 筛选无结果(即使数据库存在匹配数据) | user_year 字段类型为整型,但传入字符串 '2022' | 确保数据库字段类型与传入值一致(建议统一用字符串或整型),或使用 whereRaw('YEAR(created_at) = ?', [$year]) 基于时间戳筛选 |
✅ 进阶建议(可选)
-
使用 Eloquent 关系替代硬编码字段:若 user_year 实际表示发布年份,推荐从 created_at 自动提取:
Article::whereYear('created_at', $selectedYear)->get() - 添加搜索重置功能:在表单中增加「全部」选项(<option value="">全部年份</option>),并在控制器中跳过 where 条件。
- 启用前端无刷新筛选:结合 Axios + Vue/Alpine.js 实现 onchange 触发异步请求,提升交互体验。
通过以上结构化实现,你将获得一个健壮、可维护且符合 Laravel 官方规范的年份动态筛选功能。


















