我正在尝试解决一个非常简单的任务,但坚持使用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);
}
答案 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。以这种方式阻止用户输入并不是一个好方法,试着重新考虑你要做什么,可能有一个更好的解决方案。