Laravel排序集合传递至Vue后排序失效问题排查与解决
问题
我在Laravel中创建了一个Garbage模型,迁移文件代码如下:
Schema::create('garbages', function (Blueprint $table) { $table->id(); $table->date('disposal_at'); $table->timestamps(); });
在web.php路由中,我获取所有记录并按disposal_at排序后传递给Inertia:
Route::get('/garbage', function() { $garbages = \App\Models\Garbage::all() ->sortBy('disposal_at'); // dd($garbage); 确认Laravel中集合已按disposal_at排序 return Inertia::render('Grabage', [ 'garbages' => $garbages ]); });
Vue组件代码如下:
<script setup lang="ts"> interface Garbage { id: number, disposal_at: string } const props = defineProps<{ garbages: Garbage[] }>(); </script> <template> <ul> <li v-for="garbage in garbages" :key="garbage.id"> {{ garbage.disposal_at }} </li> </ul> </template>
但实际输出的列表并没有按disposal_at排序,而是回到了按id排序的状态,虽然在Laravel端用dd()确认集合是排序好的。
原因
Laravel的sortBy()方法返回的是保留原主键作为键名的关联集合,当Inertia将这个集合序列化为JSON传递给Vue时,会保留这些键名。而JavaScript在处理带有数字键的对象时,会自动按数字键的升序重新排列,导致Vue渲染时顺序变回原id的顺序。
解决方法
方案1:重置集合键名
在Laravel端使用values()方法重置集合的键,将其转换为连续索引的普通数组,这样序列化后Vue就能保持原排序:
Route::get('/garbage', function() { $garbages = \App\Models\Garbage::all() ->sortBy('disposal_at') ->values(); // 重置键名 return Inertia::render('Grabage', [ 'garbages' => $garbages ]); });
方案2:数据库层面排序(推荐)
直接在查询时使用orderBy()让数据库返回排序好的结果,这种方式性能更优,还能避免集合排序带来的键名问题:
Route::get('/garbage', function() { $garbages = \App\Models\Garbage::orderBy('disposal_at')->get(); return Inertia::render('Grabage', [ 'garbages' => $garbages ]); });
内容的提问来源于stack exchange,提问作者Stephan Busse
相关产品推荐
相关产品推荐

