使用jQuery .on()绑定事件重复触发及.off()失效问题咨询
事件绑定重复触发与off()失效问题解决
问题场景
当前代码中,每次调用showOrders()重新渲染DataTable后,都会执行showOrdersInModal()、changeStatus()、addUrl()三个函数绑定事件,导致事件触发次数随渲染次数递增;但如果在.on()前添加.off(),又会出现只有最后一个函数addUrl()的事件能正常执行的情况。
原代码
function changeStatus() { $('#dataTable tbody').on('change', '.orderStatus', function () {..code} } function showOrdersInModal() { $('#dataTable tbody').on('click', '.fa-eye-btn', function (e) {...code} } function addUrl() { $('#dataTable tbody').on('click', '.addUrl', function () {..code} } function showOrders() { $.ajax({ type: 'method', url: 'url', data: { data }, success: function (response) { $('#dataTable').DataTable().clear().destroy(); let data = JSON.parse('[' + response.replace(/}{/g, '},{') + ']'); $('#dataTable').DataTable( { autoWidth: false, pageLength: 25, lengthMenu: [[25, 50, 100, 500, -1], [25, 50, 100, 500, 'All']], data: data, columns: [ { data: 'receipt' }, { data: 'first_last_name' }, { data: 'contact_no' }, { data: 'address' }, { data: 'email' }, { data: 'url' }, { data: 'status' }, ], }); showOrdersInModal(); changeStatus(); addUrl(); }, }); } showOrders();
问题原因
- 不加
.off()时:每次渲染DataTable都会重复绑定相同事件,导致事件触发次数累加。 - 直接加
$('#dataTable tbody').off()时:会移除该元素上所有已绑定的事件,后面函数的.off()会覆盖前面绑定的事件,最终只剩最后一个函数的事件生效。
解决方案
方案1:精准解绑对应事件
修改三个绑定函数,在绑定前只解绑当前要绑定的事件(指定事件类型和选择器),不影响其他已绑定的事件:
function changeStatus() { // 仅解绑.orderStatus的change事件,再重新绑定 $('#dataTable tbody').off('change', '.orderStatus').on('change', '.orderStatus', function () { // ...你的业务代码 }); } function showOrdersInModal() { // 仅解绑.fa-eye-btn的click事件,再重新绑定 $('#dataTable tbody').off('click', '.fa-eye-btn').on('click', '.fa-eye-btn', function (e) { // ...你的业务代码 }); } function addUrl() { // 仅解绑.addUrl的click事件,再重新绑定 $('#dataTable tbody').off('click', '.addUrl').on('click', '.addUrl', function () { // ...你的业务代码 }); }
方案2:一次性绑定事件委托(推荐)
利用事件委托特性,把事件绑定到不会被销毁的父元素(比如#dataTable)上,只绑定一次,无需每次渲染DataTable都重复绑定:
// 页面初始化时仅绑定一次事件 $(function() { // 绑定状态变更事件 $('#dataTable').on('change', 'tbody .orderStatus', function () { // ...原changeStatus函数内的代码 }); // 绑定查看订单弹窗事件 $('#dataTable').on('click', 'tbody .fa-eye-btn', function (e) { // ...原showOrdersInModal函数内的代码 }); // 绑定添加URL事件 $('#dataTable').on('click', 'tbody .addUrl', function () { // ...原addUrl函数内的代码 }); }); function showOrders() { $.ajax({ type: 'method', url: 'url', data: { data }, success: function (response) { $('#dataTable').DataTable().clear().destroy(); let data = JSON.parse('[' + response.replace(/}{/g, '},{') + ']'); $('#dataTable').DataTable( { autoWidth: false, pageLength: 25, lengthMenu: [[25, 50, 100, 500, -1], [25, 50, 100, 500, 'All']], data: data, columns: [ { data: 'receipt' }, { data: 'first_last_name' }, { data: 'contact_no' }, { data: 'address' }, { data: 'email' }, { data: 'url' }, { data: 'status' }, ], }); // 此处不再需要调用三个绑定函数 }, }); } showOrders();
这种方法性能最优,从根源上避免了重复绑定问题。
方案3:批量解绑后统一重新绑定
在showOrders()的success回调中,先一次性解绑所有相关事件,再调用三个绑定函数:
function showOrders() { $.ajax({ type: 'method', url: 'url', data: { data }, success: function (response) { // 批量解绑所有要绑定的事件 $('#dataTable tbody') .off('change', '.orderStatus') .off('click', '.fa-eye-btn') .off('click', '.addUrl'); $('#dataTable').DataTable().clear().destroy(); let data = JSON.parse('[' + response.replace(/}{/g, '},{') + ']'); $('#dataTable').DataTable( { autoWidth: false, pageLength: 25, lengthMenu: [[25, 50, 100, 500, -1], [25, 50, 100, 500, 'All']], data: data, columns: [ { data: 'receipt' }, { data: 'first_last_name' }, { data: 'contact_no' }, { data: 'address' }, { data: 'email' }, { data: 'url' }, { data: 'status' }, ], }); showOrdersInModal(); changeStatus(); addUrl(); }, }); }
同时三个绑定函数内不需要再添加.off()。
内容的提问来源于stack exchange,提问作者Shinxx
相关产品推荐
相关产品推荐

