我正在尝试在用户单击时使元素出现和消失,并带有淡入淡出的动画。我有这个工作,但如果用户快速连续单击两次或在动画完成之前单击两次,则会出现问题。我知道问题将与运行循环以及事件和动画的时间等有关,但作为 html/js 的新手,我在这种情况下对这些问题没有足够的经验来了解最佳解决方案。
这是一个小提琴,如果您单击第一行并在每次单击之间等待几秒钟,它将起作用,如果您疯狂地单击,您很快就会开始看到问题。
谢谢
我正在尝试在用户单击时使元素出现和消失,并带有淡入淡出的动画。我有这个工作,但如果用户快速连续单击两次或在动画完成之前单击两次,则会出现问题。我知道问题将与运行循环以及事件和动画的时间等有关,但作为 html/js 的新手,我在这种情况下对这些问题没有足够的经验来了解最佳解决方案。
这是一个小提琴,如果您单击第一行并在每次单击之间等待几秒钟,它将起作用,如果您疯狂地单击,您很快就会开始看到问题。
谢谢
一个快速的解决方案就是添加一个简单的锁来防止任何额外的动画被触发。我在这里做了。
关于代码的一些注释 - 代码上的动画锁定可能不应该被代码的其他部分访问,所以我把它放在一个单独的上下文中。此外,为了确保一切都在正确的时间触发,我添加了一个整数控件“动画时间”来处理动画速率。
这是一个比您想象的更常见的问题。问题是您设置了一个事件来将您的元素设置为display: none
. 但是,如果您再次单击,您希望阻止该事件发生。因此,您需要做的是保留对事件的引用(setTimeout()
返回 this),以便clearInterval()
在需要取消隐藏元素时调用该引用:
var listener = (function() {
var interval = 0; //A variable to retain the interval
return function() { //return the original function into listener
var title = document.getElementById('title');
//dismiss any plans to hide/show the element because we've changed our minds
// (if the event already fired, this does nothing, which is fine):
clearInterval(interval);
if (title.dataset.displayed == 'yes') {
title.dataset.displayed = 'no';
setTimeout(function () {
title.style.webkitTransition = "opacity 2.0s ease";
title.style.opacity = 0.0;
}, 0);
//don't forget to hold onto the interval!
interval = setTimeout(function() { title.style.display = 'none'; }, 2000);
}
else {
title.dataset.displayed = 'yes';
title.style.display = 'block';
//It's probably not necessary to retain the interval here.
// But it doesn't hurt anything.
interval = setTimeout(function () {
title.style.webkitTransition = "opacity 2.0s ease";
title.style.opacity = 1.0;
}, 0);
}
};
}());
var li = document.getElementById('list');
li.addEventListener("click", listener, false);
请注意,我将您的侦听器函数包装在一个更大的、立即调用的函数表达式中,该表达式返回原始函数。我这样做interval
是为了从一个呼叫保留到listener()
下一个呼叫。你也可以创建interval
一个全局变量,但这些很顽皮,而且这个解决方案更加独立。
当我将它换成你的 JSFiddle 时,它似乎工作正常。剩下的代码做得很好!