Laravel中jQuery UI Sortable使用UUID时排序异常的解决方法
我之前也碰到过一模一样的问题!核心原因是jQuery UI Sortable的serialize()方法默认会把元素ID按前缀-ID的格式拆分,UUID自带的连字符会被当成前缀和ID的分隔符,导致拆分出来的ID只有UUID的第一段(比如b20s0b82),后端自然找不到对应的模型,排序功能就失效了。
下面给你两种可靠的解决办法,推荐第一种,更直观灵活:
方法一:手动构造排序数据(推荐)
这种方法避开了serialize()的默认规则,改用data-*属性存储UUID,然后手动收集排序后的UUID数组,完全不会有分隔符冲突的问题。
1. 修改视图文件(index.blade.php)
把原来的id="item-{{$blogs->uuid}}"改成用data-uuid属性存储UUID,id可以保留或者去掉(这里保留也不影响):
<tbody id="sortable"> @foreach($data['blogs'] as $blogs) <tr id="item-{{$blogs->uuid}}" data-uuid="{{$blogs->uuid}}"> <td>{{$loop->iteration}}</td> <td><img width="100" src="/images/blogs/{{$blogs->blogs_file}}" alt=""></td> <td class="sortable">{{$blogs->blogs_title}}</td> <td>{{Illuminate\Support\Str::limit($blogs->blogs_content, 15)}}</td> <td align="center" width="20"> <a href="#"><i class="fa fa-pencil-square"></i></a> </td> <td align="center" width="20"> <a href="javascript:void(0)"><i id="{{$blogs->uuid}}" class="fa fa-trash-o"></i></a> </td> </tr> @endforeach </tbody>
2. 修改jQuery代码
去掉serialize(),手动遍历排序后的<tr>,收集data-uuid的值,构造请求数据:
$(function () { $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); $('#sortable').sortable({ revert: true, handle: ".sortable", stop: function (event, ui) { // 手动收集排序后的UUID数组 var sortedItems = $('#sortable tr').map(function() { return $(this).data('uuid'); }).get(); $.ajax({ type: "POST", data: { items: sortedItems }, // 传递排序后的UUID数组 url: "{{route('blogs.Sortable')}}", success: function (msg) { if (msg) { alertify.success('İşlem Başarılı'); } else { alertify.error('İşlem Başarısız'); } } }); } }); $('#sortable').disableSelection(); });
3. 修改BlogController代码
现在接收的是items数组,根据UUID查找模型并更新排序字段:
use Illuminate\Http\Request; public function sortable(Request $request) { foreach ($request->items as $key => $uuid) { // 通过UUID查找对应博客 $blogs = Blogs::where('uuid', $uuid)->first(); if ($blogs) { $blogs->blogs_must = intval($key); $blogs->save(); } } // 返回JSON格式的响应更规范 return response()->json(true); }
方法二:修改serialize的正则表达式
如果想继续使用serialize()方法,可以自定义它的拆分规则,让它正确识别带连字符的UUID。
1. 视图文件无需修改
保持原来的<tr id="item-{{$blogs->uuid}}">即可。
2. 修改jQuery代码
在调用serialize()时,指定expression选项,用正则匹配出完整的UUID:
stop: function (event, ui) { // 自定义正则,匹配item-前缀后的所有内容(包括UUID里的连字符) var data = $(this).sortable('serialize', { expression: /^item-(.+)$/ }); $.ajax({ type: "POST", data: data, url: "{{route('blogs.Sortable')}}", success: function (msg) { if (msg) { alertify.success('İşlem Başarılı'); } else { alertify.error('İşlem Başarısız'); } } }); }
这里的正则/^item-(.+)$/会贪婪匹配item-之后的所有字符,包括UUID里的连字符,这样就能得到完整的UUID了。
3. 修改BlogController代码
和方法一类似,改成通过UUID查找模型:
use Illuminate\Http\Request; public function sortable(Request $request) { foreach ($request->item as $key => $uuid) { $blogs = Blogs::where('uuid', $uuid)->first(); if ($blogs) { $blogs->blogs_must = intval($key); $blogs->save(); } } return response()->json(true); }
两种方法都能解决问题,个人更推荐第一种,因为它不依赖serialize()的规则,后续如果UUID格式变化也不容易出问题。
内容的提问来源于stack exchange,提问作者BoraN

