使用 jQuery 的 .animate() 函数时,它通常由 mouseEnter 或 hover 事件触发。 这很好,但意味着我们需要考虑这些事件被多次触发的情况。 如果附加了 hover 事件的元素被多次悬停,这意味着动画将被触发多次,这通常是不可取的。 处理此问题的标准方法是使用 .stop() 函数,例如
$(this).stop().animate({ width: "200px" });
但这绝对不是万能的解决方案。 让我们探索一下。
我们已经知道 **不** 使用 .stop() 会有问题,因为这样动画就会排队,对于多次快速悬停来说有点尴尬。 但不使用 .stop() 在某种程度上也很好,因为 mouseEnter 动画和 mouseLeave 动画完全按顺序执行。 我在这里追求的就是这种平滑度,只是没有排队。
使用 .stop() 可以防止排队,**但它也会阻止动画完成一个完整的循环。** 鼠标移开,stop 函数就会触发,停止触发 mouseEnter 的动画,并开始重置事物的动画。
我开始折腾的第一件事是在只使用其中一个动画之前使用 .stop(),但这没有太大帮助。 .stop() 函数还有一些你可以传递的参数,第二个参数决定是否应该先强制动画完成。 如果设置为 true,动画确实会完成,但它不会平滑地完成,它会跳到最终状态,我一般觉得这种效果不可取。
解决方案在于,**只有当元素的状态没有被动画化时才开始** 新动画。 这样,你甚至不用担心排队,因为一次只能运行一个动画。 可以用几种方法实现,但我发现这个是最干净的
$("div").hover(function(){
$(this).filter(':not(:animated)').animate({ width: "200px" });
}, function() {
$(this).animate({ width: "100px" });
});
在此过程中有很多想法。 查看下面的演示,了解我所经历的所有不同选项,以及一个同样有效的方法。
更新:一定要看看 Ralf Stoltze 的 更好的解决方案.
演示页面无法访问。 我在源代码中看到了 :-/
似乎在大约一个小时前发生了什么事情。
应该已经修复了。 由于某种不可思议的原因,页面编码有问题。
它可以运行。 非常棒!
哇..!
太棒了!
谢谢!
哇,太聪明了。 谢谢! 我一直依赖 .stop(),但从不喜欢动画突然中断。
哦,我刚刚测试了演示页面。 使用你提出的新方法,当快速悬停时,所有元素都会触发动画。 我不知道自己是否讲清楚了。 例如,如果你将它用于菜单,用户快速将鼠标移过所有菜单,所有菜单都会同时触发(使用 stop() 不会发生这种情况)。
非常有趣,Chris。
我能想到一些情况下,一种方法比另一种方法更可取(运行完整的循环与不运行)。
有见地。 谢谢你的分享。
酷! 非常棒的技巧,适用于未来的项目。
很棒的探索——我一直都在解决这个问题。
如果这是一个菜单,仍然有一个主要问题。 使用过滤器的問題在於,如果你将鼠标移出元素,然后在它动画回默认状态之前再次进入元素,它将不会再次动画到悬停状态——即使你将鼠标悬停在上面。
非常混乱。 我实际上更喜欢 .stop() 解决方案——它不是最漂亮的,但它确实有效。
这完全正确。 我一开始以为 Chris 的解决方案比使用 stop() 更好,但你击中了要害。 我现在将继续使用 stop()。
对于像下拉菜单这样的东西来说,这绝对是一个很好的观点,因为悬停动画除了纯粹的美学效果之外还会做一些其他事情。
我刚刚测试了演示,似乎只有“Dequeue”版本可靠地工作。 “Animated Test” 会进行一次“循环”,然后我移开鼠标,再次悬停(动画显然已经完成),什么也不会发生。
非常棒的教程和说明。 这些在很多情况下都非常有用。
非常棒! 我现在使用
$(this).stop().animate({ width: "200px" }, {queue:false});
这样好吗?
很酷的例子,但它们似乎都有缺陷。 我更喜欢排队。
Chris,我对你的 jQuery 知识感到敬畏。 这是一个很棒的例子集! 谢谢你分享你的见解和演示!
Chris,你应该采用 Duke Nukem 的口头禅……特别是在这种情况下
“我真他妈厉害”。
演示页面上最下面那两个例子……当你触发 mouseover-事件,然后快速 mouseout 并再次 mouseover 时就会有问题。
动画将恢复到非活动状态,鼠标光标在链接上,什么也不会发生。
这确实是一个问题。 有什么解决方案吗?
长期以来一直使用 :not(:animated)。 这是最好的。 有时我会使用 queue:false,但不多,我几乎从不使用 .stop()。
Chris,再次很棒的 jQuery。 谢谢。 (
哇,很棒的解决方案,谢谢 Chris。
非常棒! 我可以在网站的两个地方立即使用它。 =)
我知道建议一个插件对那些有兴趣学习解决他们可能遇到的问题的编程解决方案的人来说并没有什么帮助(好吧,除非他们热衷于深入研究插件的源代码),但我对 hoverintent 非常满意。
默认行为并不总是适合所有情况(也取决于你想让你的测试多么不切实际),但我发现只要稍微调整一下,它就能很好地检测……嗯……你的意图……悬停!
*抱歉,题外话*
Chris,你目前在这个博客上使用的是什么类型的相关文章插件?
我的 hoverFlow 插件是另一个解决动画队列累积问题的解决方案。 它也只对单个 mouseover/-out 响应一个完整的动画循环。
http://www.2meter3.de/code/hoverFlow/
很高兴看到你也走了很长一段路(……演示页面)找到了一个好的解决方案。
hoverFlow 也解决了评论中提到的菜单问题(“快速 mouseout 并返回”)。 查看 子菜单示例。
我发现 :animated 伪选择器和保存状态到类名解决方案都太慢了(尤其是在老版本的 IE 中)。 我的方法是使用 jQuery 的 data() 函数来保存状态。
实际的动画是在一个匿名函数内部触发的,该函数被 queue()d。 这样,我就可以根据当前状态(鼠标位置)控制动画队列。
棒极了。 Ralf,这真的很酷。
这个插件很棒。我正在尝试在我的网站上找到使用它的方法。看起来真的很棒。
我用 hoverflow 很长时间了 =)……讨厌 .stop(),它对我来说根本不起作用,看起来很丑陋^^……hoverflow 才是真正的美!但感谢你指出了这个问题 Chris!
这里做的很棒!我在使用 actionscript 的 Flash 中遇到了类似的动画问题。通过使用时间轴从鼠标移开点反向播放动画,并在悬停事件中向前播放,找到了解决方案。
然而,即使是你的第一个解决方案在移动设备上也效果很好(在那里它不会使用 flash,但仍然希望如此),因为你不能用手机悬停(至少在 iPhone 上不行,我写这个的时候正在使用它)。
对于非移动用户,如何用悬停状态为菜单项编写一个下拉菜单,使其也适用于移动用户?我在浏览过的网站上遇到过这个问题,我不得不点击然后快速停止加载页面才能访问悬停菜单项……。
非常棒 Chris,我稍微定制了一下你的过滤器代码
在 .filter() 之前添加 .stop()
效果很好!
$(“#animate-test div”).hover(function(){
$(this).stop().filter(‘:not(:animated)’).animate({ width: “200px” });
}, function() {
$(this).animate({ width: “100px” });
});
做得非常好!我喜欢演示页面上有许多示例。
http://www.webappers.com/2009/12/18/a-solution-of-jquery-animation-queue-buildup/
天哪,你在这方面帮助我很多。
谢谢!:)
对于点击事件有类似的解决方案吗?
是的,我在点击事件上尝试过,它对我来说效果很好,事件并不重要,更重要的是动画是这个修复方法。
Chris,你真是太棒了!!!
这帮助了我!:–>
水烟筒坠落测试…
Chris,你的指南和教程一如既往地棒极了。无法感谢你足够多。