您可以使用.off 取消绑定您的处理程序,但有一个警告;如果你这样做只是为了防止处理程序在它已经运行时再次被触发,你需要推迟重新绑定处理程序。
例如,考虑这段代码,它使用 5 秒的热睡眠来模拟在处理程序内完成的同步和计算成本高昂的事情(比如繁重的 DOM 操作):
<button id="foo">Click Me!</div>
<script>
function waitForFiveSeconds() {
var startTime = new Date();
while (new Date() - startTime < 5000) {}
}
$('#foo').click(function handler() {
// BAD CODE, DON'T COPY AND PASTE ME!
$('#foo').off('click');
console.log('Hello, World!');
waitForFiveSeconds();
$('#foo').click(handler);
});
</script>
这行不通。正如您在this JSFiddle 中尝试的那样,如果您在处理程序已经执行时单击按钮,则处理程序将在第一次执行完成后再次执行。更重要的是,至少在 Chrome 和 Firefox 中,即使您不使用 jQuery 而是使用 addEventListener 和 removeEventListener 添加和删除处理程序也是如此。浏览器在第一次单击后执行处理程序,解除绑定和重新绑定处理程序,然后处理第二次单击并检查是否有单击处理程序要执行。
要解决这个问题,您需要使用setTimeout 推迟处理程序的重新绑定,以便在第一个处理程序执行时发生的点击将在您重新附加处理程序之前处理。 p>
<button id="foo">Click Me!</div>
<script>
function waitForFiveSeconds() {
var startTime = new Date();
while (new Date() - startTime < 5000) {}
}
$('#foo').click(function handler() {
$('#foo').off('click');
console.log('Hello, World!');
waitForFiveSeconds();
// Defer rebinding the handler, so that any clicks that happened while
// it was unbound get processed first.
setTimeout(function () {
$('#foo').click(handler);
}, 0);
});
</script>
您可以在 this modified JSFiddle 看到这一点。
当然,如果您在处理程序中执行的操作已经是异步的,则这是不必要的,因为您已经将控制权交给了浏览器,并在重新绑定处理程序之前让它刷新所有点击事件。例如,这样的代码在没有setTimeout 调用的情况下也能正常工作:
<button id="foo">Save Stuff</div>
<script>
$('#foo').click(function handler() {
$('#foo').off('click');
$.post( "/some_api/save_stuff", function() {
$('#foo').click(handler);
});
});
</script>