如何在setTimeout运行期间阻止点击事件生效,修复快速点击导致的轮播逻辑异常
问题原因&解决方案
根本问题定位
首先你写的点击事件锁逻辑完全没有生效,核心错误有两个:
- 点击事件末尾的
playForbidden == true是相等判断语句,不是赋值操作,playForbidden变量永远不会变成true,你写的防重复点击判断相当于不存在 - 重启轮播的500ms延迟期间没有保持锁状态,也没有存储清理setTimeout的id,快速点击会生成多个待执行的定时器任务,导致轮播逻辑紊乱
修复方案
不需要用stopPropagation或者preventDefault,只需要修正状态锁逻辑、补充定时器清理逻辑即可,修改后的JS代码如下:
var j = 0; var myElements = document.querySelectorAll('.div_child'); var myButton = document.querySelector('.my_button'); var restartTimeoutId = null; // 新增变量存储重启的timeout id var colorArray = [] for (let i = 0; i < myElements.length; i++) { let currentColor = getComputedStyle(myElements[i]).backgroundColor; colorArray[i] = currentColor; } function my_fonction() { myElements[j].style.opacity = 1; for (let k = 0; k < myElements.length; k++) { if (k != j) { myElements[k].style.opacity = 0; } } j++; if (j == myElements.length) { j = 0 } playForbidden = false; } function setIntervalAndExecuteFn(fn, t) { fn(); return (setInterval(fn, t)); } var myIndice = j; var myIntervalId = setIntervalAndExecuteFn(my_fonction, 1000); var play = true; var playForbidden = false; myButton.addEventListener('click', function() { if (playForbidden) return; playForbidden = true; // 先上锁 if (play) { play = false; clearInterval(myIntervalId); // 如果有未执行的重启任务先清掉 if (restartTimeoutId) { clearTimeout(restartTimeoutId); restartTimeoutId = null; } myIndice = j == 0 ? myElements.length - 1 : j - 1; myButton.style.backgroundColor = colorArray[myIndice]; playForbidden = false; // 暂停操作完成直接解锁 } else { play = true; myButton.style.backgroundColor = 'transparent'; restartTimeoutId = setTimeout(function() { myIntervalId = setIntervalAndExecuteFn(my_fonction, 1000); restartTimeoutId = null; // 重启完成后再解锁 }, 500); } });
修改点说明
- 修正了
playForbidden的赋值错误,点击时先上锁,对应操作完成后再解锁 - 新增
restartTimeoutId存储延迟重启的定时器id,每次触发点击时先清理未执行的重启任务,避免多个定时器叠加 - 重启轮播的500ms延迟期间保持
playForbidden为true,这段时间的点击会直接被拦截,直到重启完成后才放开锁
内容的提问来源于stack exchange,提问作者user14844032
相关产品推荐
相关产品推荐

