Firefox浏览器中DataTable排序二次点击失效问题问询
DataTable排序在Firefox二次点击失效问题排查与修复
问题现象
DataTable自定义排序功能在Chrome中运行正常,但Firefox下首次点击排序列可正常工作,第二次点击后无任何反应。
核心原因分析
table.ajax.json()的浏览器差异:Firefox中该方法仅在真实AJAX请求完成后才会存储响应数据,第二次点击时因为skipAjax=true跳过了真实请求,此时无法正确获取上次响应数据,导致排序逻辑无数据可处理。- 状态保存逻辑冲突:开启
stateSave: true后,DataTable自动保存表格状态,手动修改响应数据重绘的操作会和自动保存的状态冲突,导致Firefox中重绘不生效。 - 表头选择器错误:
adjustSortIcon函数中$("th.sortable", 0)的上下文参数无效,无法正确选中目标表头,导致排序状态图标更新异常,同时可能影响后续点击逻辑。
修复方案
- 缓存AJAX响应到全局变量:不再依赖
table.ajax.json(),在每次真实AJAX请求完成后缓存响应数据,手动排序时直接使用缓存数据。 - 关闭状态保存:暂时关闭
stateSave(若业务不需要状态持久化),避免自动状态与手动排序逻辑冲突。 - 修正表头选择器:确保
adjustSortIcon能正确选中排序列表头。 - 优化排序逻辑:补充排序相等情况的返回值,避免排序不稳定问题。
修改后的完整代码
JavaScript部分
$(document).ready(function () { setUpTable(); }); function setUpTable() { var skipAjax = false; var skipAjaxDrawValue = 0; var isSortAscending = true; var lastAjaxResponse = null; // 新增:缓存上次AJAX响应 table = $("#paymentTable").DataTable({ bProcessing: false, bSort: false, destroy: true, dom: '<"top"i>rt<"bottom"lp><"clear">', info: false, paging: false, serverSide: true, stateSave: false, // 修改:关闭状态保存避免冲突 targets: "no-sort", ajax: { dataType: "JSON", type: "POST", url: "/BeneficiaryPayment/Search", data: function (data) { if (skipAjax) { skipAjaxDrawValue = data.draw; } return data; }, beforeSend: function () { if (skipAjax) { if (!lastAjaxResponse) return false; // 无缓存数据则终止 // 复制缓存数据,避免修改原数据 const response = {...lastAjaxResponse}; response.draw = skipAjaxDrawValue; isSortAscending = !isSortAscending; // 执行排序逻辑,补充相等情况的返回值 response.data.sort((r1, r2) => { if (r1.TransactionDate < r2.TransactionDate) { return isSortAscending ? -1 : 1; } else if (r1.TransactionDate > r2.TransactionDate) { return isSortAscending ? 1 : -1; } return 0; }); adjustSortIcon(isSortAscending); this.success(response); skipAjax = false; return false; } showSpinner(); return true; }, success: function(response) { // 新增:缓存成功响应的数据 lastAjaxResponse = response; }, complete: function () { removeSpinner(); } }, aoColumns: [ { className: "details-control", orderable: false, data: null, defaultContent: "", render: (data) => { if (!data.Beneficiaries?.length && !data.ForwardDrawdowns?.length) return ""; const plus_sign = data.ForwardDrawdowns?.length > 0 ? "plus-sign-secondary" : "plus-sign"; return `<i class="flag ${plus_sign} hasPointer" aria-hidden="true"></i>` } }, { mDataProp: (_data, _type, full) => getActionButtons(_data) }, { mDataProp: "DisplayTransactionDate" }, { mDataProp: (_data, _type, full) => getEditClientLink(_data) }, { mDataProp: "ClientId" }, { mRender: (_data, _type, full) => getTradeTransactionLink(full) }, { mDataProp: "DisplaySoldAmount" }, { mRender: (_data, _type, full) => getDisplayBoughtAmount(full) }, { mDataProp: "Destination" }, { mDataProp: "PaymentMethod" }, { mDataProp: "Partner" }, { mRender: (_data, _type, full) => getDisplayPaymentStatus(full["DisplayPaymentStatus"]) }, { mRender: (_data, _type, full) => getDisplayRiskGrade(full["DisplayRiskGrade"]) } ], initComplete: function() { $("#btnSearch").on("click", e => { const searchText = $("#search").val().trim(); window.localStorage.setItem(searchTextKey, searchText); const paymentStatus = $("#paymentStatuses").val(); window.localStorage.setItem(paymentStatusKey, paymentStatus); table.columns(0).search(searchText); table.columns(1).search(paymentStatus); isSortAscending = true; adjustSortIcon(isSortAscending); table.draw(); e.preventDefault(); }); table.on("click", "th.sortable", function() { skipAjax = true; table.draw(); } ); }, "columnDefs": [ { type: "currency", targets: [colSoldAmount, colBoughtAmount ] } ], rowCallback: rowCallback }); } function adjustSortIcon(isSortAscending) { // 修改:修正选择器,正确选中排序列表头 const cell = $("#paymentTable thead th.sortable"); if (isSortAscending) { cell.removeClass("sorting_desc").addClass("sorting_asc"); } else { cell.removeClass("sorting_asc").addClass("sorting_desc"); } }
HTML部分(无需修改)
<table id="paymentTable" class="table table-striped table-hover"> <thead> <tr> <th></th> <th></th> <th class="sortable sorting_asc">Transaction Date</th> <th>Client</th> <th>Client Id</th> <th>Deal Id</th> <th class="text-right">Client Sold</th> <th class="text-right">Client Bought</th> <th>Destination</th> <th>Payment Method</th> <th>Partner</th> <th class="text-center">Payment Status</th> <th class="text-center">Risk Grade</th> </tr> </thead> </table>
额外说明
如果业务需要保留stateSave功能,需手动处理状态保存逻辑,在手动排序后更新保存的状态,避免与自动保存的状态冲突。
内容的提问来源于stack exchange,提问作者Alisa T
相关产品推荐
相关产品推荐

