启用后,“禁用”按钮会引发单击事件

时间:2014-01-13 19:20:19

标签: javascript jquery

我正在尝试解决一个非常简单的任务,但坚持使用JQuery行为。

我有一个HTML按钮,我点击后立即禁用(添加禁用属性)以防止多次点击,做一些长时间运行(即更新带有大量元素的DOM)并启用按钮回来。

问题是,即使按钮被禁用,jquery也会对其进行所有点击,并在启用后立即启动我的点击处理程序。

根据JQuery文档,它不应该为禁用的元素引发事件。

贝娄是我的代码。打开JS控制台,在按钮上单击两次,在控制台中注意“START - ”消息。

<div>
<button id="mybtn" type="button">Find</button>
</div>

var btnElement = $('#mybtn');
btnElement.click(doClick);

           function doClick() {
               var btnElement = $('#mybtn');
               btnElement.attr('disabled', true);

               console.log('START --' + Date());
               for (var i = 0; i < 70000; i++) {
                   var el = $('#mybtn');
                   var w = el.width();
                   w += 10;
               }
               console.log('STOP --' + Date());
               el.attr('disabled', false);
           }

1 个答案:

答案 0 :(得分:1)

这是我的解决方案http://jsfiddle.net/DRyxd/8/

var btnElement = $('#mybtn');
var buttonIsBusy = false;

function doHeavyJob () {
    console.log('START --' + Date());
    for (var i = 0; i < 70000; i++) {
        var el = $('#mybtn');
        var w = el.width();
        w += 10;
    }
    var timeoutId = setTimeout (unblockTheButton, 0);
    console.log('STOP --' + Date());
}

function unblockTheButton () {
    console.log('unblockTheButton');
    btnElement.attr('disabled', false);
    buttonIsBusy = false;
}

function doClick() {
    console.log('click', buttonIsBusy);
    if (buttonIsBusy) {
        return;
    }

    btnElement.attr('disabled', true);
    buttonIsBusy = true;

    var timeoutId = setTimeout (doHeavyJob, 0);
}


btnElement.click(doClick);

这里的问题是点击处理程序功能还没有完成,浏览器还没有刷新DOM。这意味着block尚未应用于按钮。您可以尝试将重代码推出当前上下文,如下所示:

function someHeavyCode () {
    /* do some magic */
}
var timeoutId = setTimeout(someHeavyCode, 0);

这会将你的重代码推出当前的上下文。让浏览器首先更新DOM,并且只在执行繁重的代码之后。

执行繁重代码时,浏览器(至少Chrome)会将用户输入队列保留在其他位置(或最可能是其他线程)。一旦繁重的代码完成 - 它就会为DOM提供所有排队的事件。我们需要以某种方式忽略这些事件。然后我再次使用带有0次的setTimeout。让浏览器执行排队等待排除按钮之前的内容。

警告但要非常小心这项技巧。浏览器仍然会被阻止,如果你产生了很多这样的块,它可能会挂起。 另请参阅此Why is setTimeout(fn, 0) sometimes useful?并考虑使用网络工作者。

P.S。以这种方式阻止用户输入并不是一个好方法,试着重新考虑你要做什么,可能有一个更好的解决方案。