如何在Laravel中实现跨多视图持久化的全局过滤器?
Laravel全局筛选栏跨页面保持状态的实现方案
下面是几种高效且实用的实现方式,你可以根据需求选择:
1. Session存储筛选状态(最常用)
直接把筛选参数存入Session,所有需要应用筛选的页面从Session读取参数,状态在用户会话内持续有效。
实现步骤:
- 提交筛选时存储参数:在处理筛选提交的控制器方法中,将请求参数存入Session:
public function applyFilters(Request $request) { // 先验证参数合法性 $validated = $request->validate([ 'month' => 'nullable|integer|between:1,12', 'status' => 'nullable|in:completed,pending,canceled' ]); // 存入Session,可指定过期时间 session()->put('trade_filters', $validated, now()->addDay()); return redirect()->back(); } - 查询时应用筛选:在交易、报表的控制器查询逻辑中,从Session取出参数并应用:
public function index() { $filters = session()->get('trade_filters', []); $trades = Trade::query() ->when(isset($filters['month']), function ($query) use ($filters) { $query->whereMonth('created_at', $filters['month']); }) ->when(isset($filters['status']), function ($query) use ($filters) { $query->where('status', $filters['status']); }) ->get(); return view('trades.index', compact('trades')); } - 清除筛选:添加清除按钮,触发方法删除Session中的筛选参数:
public function clearFilters() { session()->forget('trade_filters'); return redirect()->back(); } - 表单回显:在全局筛选栏的表单中,默认填充当前Session的筛选值:
<input type="number" name="month" min="1" max="12" value="{{ session('trade_filters.month') }}"> <select name="status"> <option value="">全部状态</option> <option value="completed" {{ session('trade_filters.status') == 'completed' ? 'selected' : '' }}>已完成</option> <option value="pending" {{ session('trade_filters.status') == 'pending' ? 'selected' : '' }}>待处理</option> </select>
2. URL查询参数持久化(支持状态分享)
将筛选参数附加到所有相关导航链接中,跳转时参数随URL传递,优点是状态可通过URL分享给他人。
实现步骤:
- 生成带筛选参数的链接:创建全局辅助函数(在
app/helpers.php中),自动拼接当前筛选参数到路由:if (!function_exists('route_with_filters')) { function route_with_filters(string $name, array $params = []): string { // 获取当前请求中的筛选参数 $filters = request()->only(['month', 'status']); // 合并路由参数与筛选参数 return route($name, array_merge($params, $filters)); } } - 视图中使用辅助函数:所有相关导航链接改用这个辅助函数生成:
<a href="{{ route_with_filters('trades.index') }}">交易列表</a> <a href="{{ route_with_filters('reports.index') }}">交易报表</a> - 控制器读取参数:直接从请求中获取参数应用筛选:
public function index(Request $request) { $month = $request->get('month'); $status = $request->get('status'); $reports = Report::query() ->when($month, fn($q) => $q->whereMonth('trade_date', $month)) ->when($status, fn($q) => $q->where('trade_status', $status)) ->get(); return view('reports.index', compact('reports')); }
3. 混合方案(兼顾持久化与可分享性)
优先读取URL参数,若没有则从Session获取,同时将有效参数同步到Session,兼顾两种方案的优点。
核心逻辑示例:
public function index(Request $request) { // 优先取URL参数,无则取Session $month = $request->get('month', session('trade_filters.month')); $status = $request->get('status', session('trade_filters.status')); // 若有有效参数,同步更新Session $validated = []; if ($month) $validated['month'] = $month; if ($status) $validated['status'] = $status; if (!empty($validated)) { session()->put('trade_filters', $validated); } // 应用筛选查询 $data = Trade::query() ->when($month, fn($q) => $q->whereMonth('created_at', $month)) ->when($status, fn($q) => $q->where('status', $status)) ->get(); return view('trades.index', compact('data')); }
4. 全局中间件自动应用筛选(减少重复代码)
编写全局中间件,自动为指定模型添加查询范围,无需在每个控制器重复编写筛选逻辑。
实现步骤:
- 创建中间件:
php artisan make:middleware ApplyTradeFilters - 编写中间件逻辑:
namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use App\Models\Trade; class ApplyTradeFilters { public function handle(Request $request, Closure $next) { $filters = $request->only(['month', 'status']) ?: session('trade_filters', []); if (!empty($filters)) { // 为Trade模型添加全局查询范围 Trade::addGlobalScope('trade_filters', function ($query) use ($filters) { $query->when(isset($filters['month']), fn($q) => $q->whereMonth('created_at', $filters['month'])); $query->when(isset($filters['status']), fn($q) => $q->where('status', $filters['status'])); }); // 同步更新Session session()->put('trade_filters', $filters); } return $next($request); } } - 注册中间件:在
app/Http/Kernel.php的$middlewareGroups中,将中间件添加到web组或专门的交易路由组:protected $middlewareGroups = [ 'web' => [ // ...其他中间件 \App\Http\Middleware\ApplyTradeFilters::class, ], ]; - 控制器简化查询:此时控制器中无需手动添加筛选逻辑,直接查询即可:
public function index() { // 自动应用筛选条件 $trades = Trade::get(); return view('trades.index', compact('trades')); }
内容的提问来源于stack exchange,提问作者NoLimitLondon
相关产品推荐
相关产品推荐

