点击网格元素时嵌套setTimeout被其他点击中断的问题求助
问题根源:全局变量被覆盖
你代码里的elem = $(this);没有用let/const/var声明,导致elem变成了全局变量。每次点击新的.grid-item时,这个全局的elem都会被替换成当前点击的元素对象。
当你快速点击第二个元素时,第一个元素的第一个setTimeout回调还没执行,全局elem已经被换成第二个元素了。等第一个setTimeout触发时,complete_item_anim(elem)操作的是第二个元素,而第一个元素的后续动画逻辑就彻底丢失了——因为后续嵌套的setTimeout里的elem也指向了第二个元素,自然不会再处理第一个元素。
修复方案
把elem改成局部变量,用const(或let)声明,确保每个点击事件的回调都持有自己独立的元素引用:
function complete_item_anim(obj) { obj.find('.orderitemprogressbar_text_status').fadeOut(200); obj.find('.orderitemprogressbar_text_done').fadeIn(200); obj.find('.order_item_box').addClass('completed'); } $('.grid-item').click(function(event) { // 用const声明局部变量,避免全局污染 const elem = $(this); elem.find('.oitpb_percent').text('100%'); elem.find('.oitpb_time').text('0m'); elem.find('.oitpb_time_group').css('max-width', 0); elem.find('.orderitemprogressbar_green').css('width', '100%'); setTimeout(function() { complete_item_anim(elem); setTimeout(function() { elem.find('.order_item_box').addClass('removed'); setTimeout(function() { elem.remove(); }, 500); }, 600); }, 600); });
额外优化建议
如果需要支持用户中途取消某个元素的动画(比如重复点击同一个元素),可以给每个元素绑定自己的timeout ID,点击时先清除之前的timeout:
function complete_item_anim(obj) { obj.find('.orderitemprogressbar_text_status').fadeOut(200); obj.find('.orderitemprogressbar_text_done').fadeIn(200); obj.find('.order_item_box').addClass('completed'); } $('.grid-item').click(function(event) { const elem = $(this); // 清除当前元素已有的所有timeout if (elem.data('timeouts')) { elem.data('timeouts').forEach(id => clearTimeout(id)); } elem.find('.oitpb_percent').text('100%'); elem.find('.oitpb_time').text('0m'); elem.find('.oitpb_time_group').css('max-width', 0); elem.find('.orderitemprogressbar_green').css('width', '100%'); const timeouts = []; const timeout1 = setTimeout(function() { complete_item_anim(elem); const timeout2 = setTimeout(function() { elem.find('.order_item_box').addClass('removed'); const timeout3 = setTimeout(function() { elem.remove(); }, 500); timeouts.push(timeout3); }, 600); timeouts.push(timeout2); }, 600); timeouts.push(timeout1); // 把timeout ID存在元素的data里 elem.data('timeouts', timeouts); });
这样用户重复点击同一个元素时,会先终止之前的动画流程,重新开始新的,体验更友好。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

