Laravel 8中通过Ajax实现无刷新页面重载div及数据表格
问题原因
你当前代码不生效的核心问题有5个:
load()方法使用错误:jQuery的load()第一个参数必须是服务端请求地址,你写$("#tbody").load("#tbody")本质是请求当前页面的#tbody锚点,不会发起服务端请求拉取最新数据- 事件绑定逻辑错误:你把表格刷新逻辑绑定在
saveBtn的click事件里,还嵌套在表单submit回调内部,既会导致事件重复绑定,也会因为表单submit默认触发时机问题,刷新逻辑根本不会在数据提交成功后执行 - DataTables插件冲突:你手动修改DOM的方式和DataTables的内部缓存机制不兼容,哪怕手动插入新行,插件也识别不到,分页、排序功能会异常
- 回调逻辑缺失:ajax提交成功的回调里只做了重置表单、关闭弹窗操作,根本没有执行任何表格更新动作
- 额外小bug:blade模板里操作按钮的
data-id属性用了PHP字符串拼接写法' . $row->id . ',会直接把点号输出到页面上,后续编辑删除功能拿不到正确的书籍ID
正确实现方案
给你两种可落地的实现,优先选第二种,和DataTables适配性更好。
方案一:保留现有DOM渲染逻辑,局部重载tbody
1. 调整控制器
在BookController里新增一个专门返回表格tbody内容的接口,原有的index和insert方法保留:
// 新增方法,返回渲染好的tbody HTML public function getBookTbody() { $books = Book::all(); return view('partials.book_tbody', compact('books'))->render(); }
2. 拆分视图
新建resources/views/partials/book_tbody.blade.php,把原来写在tbody里的循环内容挪过去,修正data-id的写法错误:
@foreach ($books as $row) <tr> <th scope="row">{{ $row->id }}</th> <td>{{$row->title }}</td> <td>{{ $row->author }}</td> <td> <a href="javascript:void(0)" data-id="{{ $row->id }}" class="edit btn btn-primary btn-sm editBook">Edit</a> <a href="javascript:void(0)" data-id="{{ $row->id }}" class="btn btn-danger btn-sm deleteBook">Delete</a> </td> </tr> @endforeach
原来的books.blade.php里的tbody部分改成引入partial,首次加载直接渲染:
<tbody id="tbody"> @include('partials.book_tbody') </tbody>
3. 补全路由
在routes/web.php里注册新接口:
Route::get('/books/tbody', [BookController::class, 'getBookTbody'])->name('book.tbody'); // 保留原有book.index、book.add路由
4. 修正JS逻辑
删掉错误的事件绑定,把刷新逻辑移到ajax成功回调里,处理DataTables兼容问题:
// 存下DataTable实例,方便后续销毁重建 const bookTable = $("#datatables").DataTable({}); $("#bookForm").submit(function(e) { e.preventDefault(); $.ajax({ type: "POST", url: "{{route('book.add')}}", data: $(this).serialize(), // 直接序列化表单,不用手动拿每个字段 success: function(response) { if (response) { $("#bookForm")[0].reset(); $("#addmodel").modal("hide"); // 拉取最新tbody内容替换 $("#tbody").load("{{ route('book.tbody') }}", function() { // 销毁旧实例重新初始化,解决DataTables缓存不更新问题 bookTable.destroy(); $("#datatables").DataTable({}); }); } }, error: function(xhr) { console.log(xhr.responseText); alert('提交失败,请重试'); } }); });
方案二:使用DataTables原生ajax重载(推荐)
不用拆分视图、不用手动操作DOM,稳定性更高:
1. 调整控制器
新增返回书籍列表JSON的接口:
public function bookList() { return response()->json(Book::all()); }
2. 补全路由
Route::get('/books/list', [BookController::class, 'bookList'])->name('book.list');
3. 调整视图和JS
把原来tbody里的@foreach循环全部删掉,tbody留空即可,DataTables会自动渲染行:
<tbody id="tbody"></tbody>
修改DataTables初始化配置,新增成功后直接调用插件自带的reload方法:
const bookTable = $("#datatables").DataTable({ ajax: "{{ route('book.list') }}", columns: [ {data: 'id', title: 'Book_ID'}, {data: 'title', title: 'Book_Name'}, {data: 'author', title: 'Auther'}, { data: 'id', title: 'Action', render: function(id) { return `<a href="javascript:void(0)" data-id="${id}" class="edit btn btn-primary btn-sm editBook">Edit</a> <a href="javascript:void(0)" data-id="${id}" class="btn btn-danger btn-sm deleteBook">Delete</a>` } } ] }); $("#bookForm").submit(function(e) { e.preventDefault(); $.ajax({ type: "POST", url: "{{route('book.add')}}", data: $(this).serialize(), success: function(response) { if (response) { $("#bookForm")[0].reset(); $("#addmodel").modal("hide"); // 直接调用DataTables原生重载方法,自动拉取最新数据渲染 bookTable.ajax.reload(); } }, error: function(xhr) { console.log(xhr.responseText); alert('提交失败,请重试'); } }); });
两种方案都能实现无刷新局部更新表格,方案二后续做编辑、删除、搜索、分页的扩展更方便,不会出现DOM和插件状态不一致的问题。
内容的提问来源于stack exchange,提问作者Mubeen Ahmad
相关产品推荐
相关产品推荐

