14

我的网页上有一个搜索框,其中包含复选框,以便用户过滤他们的结果。一次只能选中一个复选框。

单击复选框时,我的代码会运行并将过滤器应用于列表并返回正确的结果。

我遇到的问题是,当一个复选框被快速连续单击多次时,它会将请求排队并将它们一一拉回来。如果选中一个复选框然后多次取消选中,这可能需要一段时间。

Javascript中是否有任何方法可以通知该函数它已被再次调用并且它应该停止除最后一个请求之外的所有内容?

4

3 回答 3

17

你想把你的onclick回调包装在一个去抖动的函数中,比如

http://underscorejs.org/#debounce

说你有这个

function search() {
    // ...
}

$jquery(".myFilterCheckboxes").click(search);

您应该能够将以上内容更改为:

// Only allow one click event / search every 500ms:
$jquery(".myFilterCheckboxes").click(_.debounce(search, 500));

那里有大量的去抖动函数,如果你不能或不想包含 underscore.js,那么编写自己的函数真的没什么大不了的。

我的第一个想法是去抖动,因为您提到多次点击会在短时间内创建多个事件。去抖动通常用于诸如预先输入搜索或自动完成之类的事情,以在按键之间提供一点空间来思考时间。

正如其他人所提到的,在搜索运行时简单地禁用复选框/单击事件可能更有意义。在这种情况下,请尝试以下操作:

function disableClick(elem) {
  elem.unbind("click");
  elem.attr("disabled", true);
}

function enableClick(elem, onclick) {
  // Enable click events again
  elem.live("click", search);
  // Enable the checkboxes
  elem.removeAttr("disabled");
}

function search() {
  var boxes = $jquery(".myFilterCheckboxes");
  disableClick(boxes);
  $.get(...).always(function() {
    enableClick(boxes, search);
  });
}

$jquery(".myFilterCheckboxes").live("click", search);

为什么要禁用点击事件,将禁用属性添加到复选框而不仅仅是全局锁定变量?好吧,全局锁可能有点容易出错,但更重要的是,我们已经有了一个在 DOM 中很重要的全局对象。如果我们只是修改 DOM 状态,我们会得到正确的行为并向我们的用户发出信号,他们应该在复选框上冷静下来,直到搜索完成。

也就是说,对于任何类型的锁定/解除绑定场景,通过加载微调器或您正在做的事情向用户指示可能是有意义的。

于 2014-08-04T13:18:01.920 回答
12

您可以使用锁定模式:

http://jsfiddle.net/RU6gL/

HTML

<input type="checkbox" onclick="fire()" >CB1
<br />
<input type="checkbox" onclick="fire()" >CB2

JS

function_lock = false

fire = function() {
    // First, check the lock isn't already reserved. If it is, leave immediately.
    if (function_lock) return;

    // We got past the lock check, so immediately lock the function to 
    // stop others entering
    function_lock = true;

    console.log("This message will appear once, until the lock is released")

    // Do your work. I use a simple Timeout. It could be an Ajax call.
    window.setTimeout(function() {
        // When the work finishes (eg Ajax onSuccess), release the lock.
        function_lock = false;
    }, 2000);
}

在这个例子中,该函数只会运行一次,无论复选框被点击多少次,直到超时2秒后锁被释放。

这种模式非常好,因为它可以让您在释放锁时控制 opver,而不是依赖像“去抖动”这样的定时间隔。例如,它将与 Ajax 一起使用。如果您的复选框触发了 Ajax 调用来进行过滤,您可以:

  1. 在第一次单击时,设置锁定
  2. 调用 Ajax 端点。后续单击不会调用 Ajax 端点。
  3. 在 Ajax 成功函数中,重置锁。
  4. 现在可以再次单击复选框。

HTML

<input type="checkbox" onclick="doAjax()" >CB2

JS

ajax_lock = false

doAjax: function() {
    // Check the lock.
    if (ajax_lock) return;

    // Acquire the lock.
    ajax_lock = true;

    // Do the work.
    $.get("url to ajax endpoint", function() {
         // This is the success function: release the lock
         ajax_lock = false;
    });   
} 
于 2014-08-04T13:24:07.227 回答
4

这里的问题是复选框被反复点击。您应该在处理时禁用您的复选框(这也会禁用元素上的单击事件),然后在完成处理后重新启用您的复选框。

去抖动是一个好主意,但您并不总是知道您的处理功能需要多长时间才能完成。

这是一个简单的例子,使用 jquery 承诺在一些处理后重新启用复选框 http://jsfiddle.net/94coc8sd/

使用以下代码:

function processStuff() {
    var dfd = $.Deferred();

    // do some processing, when finished, 
    // resolve the deferred object
    window.setTimeout(function(){
        dfd.resolve();
    }, 2000);

    return dfd.promise();
}

function startProcessing() {
    $('#processingCheckbox').attr('disabled', 'disabled');
     var promise = processStuff();    
    promise.done(enableCheckbox);
}

function enableCheckbox() {
    $('#processingCheckbox').removeAttr('disabled');
}

$('#processingCheckbox').on('click', startProcessing);
于 2014-08-04T15:59:37.880 回答