jQuery 的 slideUp 和 slideDown 动画
jQuery 可以通过调用 animate 方法添加动画效果, 而且还提供了一套别名, 使用起来很是方便. 其中 slideDown 和 slideUp 两方法的作用是纵向展开和卷起一个页面元素, 被使用的几率很高, 却一直存在一个小问题.
如果目标元素是被外部事件驱动, 当鼠标快速地连续触发外部元素事件, 动画会滞后的反复执行, 相当不美观 (演示页面). 演示页面中有一个按钮, 请用鼠标迅速地来回划过...
不知道本博客的老读者是否记得我写过的一个关于菜单导航的专题, 其中一节讨论的是滚动导航菜单的实现方法 (演示页面), 实现了类似 slideUp 和 slideDown 的效果, 但是不存在上述问题, 因为它的滚动高度是即时计算的, 而 jQuery 作为一个通用框架应用的面很广, 很难做到这一点.
如果用 jQuery 来实现这样的效果, 该如何处理呢?
其实很简单, 只需在触发元素上的事件设置为延迟处理, 即可避免滞后反复执行的问题. 例如: 当鼠标滑过按钮后 0.2 秒, 菜单才会展开, 如果鼠标离开按钮, 展开的处理将被终止. 也就是说, 想要展开菜单鼠标必须有 0.2 秒的事件停留在按钮上, 那么迅速地划过按钮是无法执行展开事件的. 卷起也是如此.
下面我们用代码来解决这个问题.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // 线程 IDs var mouseover_tid = []; var mouseout_tid = []; jQuery(document).ready(function(){ jQuery('#menus > li').each(function(index){ jQuery(this).hover( // 鼠标进入 function(){ var _self = this; // 停止卷起事件 clearTimeout(mouseout_tid[index]); // 当鼠标进入超过 0.2 秒, 展开菜单, 并记录到线程 ID 中 mouseover_tid[index] = setTimeout(function() { jQuery(_self).find('ul:eq(0)').slideDown(200); }, 400); }, // 鼠标离开 function(){ var _self = this; // 停止展开事件 clearTimeout(mouseover_tid[index]); // 当鼠标离开超过 0.2 秒, 卷起菜单, 并记录到线程 ID 中 mouseout_tid[index] = setTimeout(function() { jQuery(_self).find('ul:eq(0)').slideUp(200); }, 400); } ); }); }); |
看看处理过后的效果.
演示页面
注意: 当鼠标悬停时间小于动画时间时, 同样可能出现反复执行现象, 可以考虑将悬停时间设置比动画时间稍长.
嗯, 问题解决了, 但 jQuery 应该还存在其他类似的问题, 如 fadeIn 和 fadeOut (演示页面), 处理方法类似. 如果你选用 jQuery 发现了这类问题, 又不情愿为此重新写一大段代码, 那这应该算是一个不错的解决办法, 而且效果也还行. 现在本博客的 RSS feed 列表也是这样实现的.
最后, 拓展一下思维. 不知道你是否见过网页上有这样的效果: 当鼠标在某个元素上停顿一定的时候后页面上某些内容会被激活. 这样的效果处理方法和上面说到的其实是大同小异, 有兴趣的同学可自行尝试.

占上沙发...
板凳!
这个Demo似曾相识,锋利的jQuery里?忘了
我以前发给你那个jQuery插件也是实现mouseover事件延迟的,扩展性强些,如果页面上大量应用了这些动画效果的话可以挂上那个插件。
另外你写的这段代码可以改写成两个函数,方便多次调用啊
做个 小 板凳 学习下。
我做滑动展开feed订阅时就是这么做的,我设置了100毫秒(貌似太短了,回头加长点吧),想一块去了。。
第一次感觉离大师如此近。。。
click事件还是不好处理……
前排圍觀~~~
谢谢咯,呵呵.有机会来成都耍哈
这个我一直有疑问来着,现在总算有解决方法了
没根本解决。移动鼠标如果能掌握那个0.2秒的规律还是存在这个问题. 不过一般客户不会这样。呵呵
已经算很完美的解决方案了。
这里聚集了这么多搞前台的?
我在6.3的按钮上玩了半天:)~
好东西 收藏一下
围观技术贴…
围观一下~~·看的不是太懂。。
好巧,今天看到 CSSTricks 上也写了篇关于这个问题的。他的解决方法好像相当简单啊。
http://css-tricks.com/full-jquery-animations/
新文章跳票了?
如18楼所说. 真的好巧. 偶也是刚好看到这篇. 只要加上 stop(true, false) 即可解决.
http://css-tricks.com/examples/jQueryStop/
但延迟执行的处理其它时候也可能会用到
jQuery的hover事件,没有判断event的relatedtarget,所以在悬停的时候,在hover中定义的方法会不断地被执行。
可以判断鼠标的来源(relatedtarget),已经触发过hover,就可以不再触发,这也是这个问题更好的解决方法。可以参考一下mootools的mouseenter的定义。
延时仍然不是根本的解决方法,如果动画时间较长,这个问题仍然会重演。
细节的问题也要很讲究~~
我的RSS订阅是加一个判断 is(":animated") 来阻止再触发
@Xu.hel
我明年一定要去成都玩一次. 你备钱请客吧, 哈~
@sky
如果把悬停时间设置比动画时间稍长就不会发生这个问题了.
@underone
好玩不?
@Justice
哦~ 这个很好, 我要细细得看一遍, 谢谢哈~
@bolo
我敲错日期了, 改了一下都被你看到了...
@Gaze , @Kael
嗯, 很好. 我又学到一招了.
这个解决方法不错,记得以前在cssrain的网站上面好像也看到了一个解决方法,原理都是延迟。
嗨 mg12 谢谢你写了这么详细的教程。我学到很多东西。:)
我想修改一下滑动方向的时候,却不知道怎么下手。你能帮我一下吗?
我想把下滑的动作slideDown,改成往上滑。因为我的导航bar是在页面最下面,我想滑出的菜单是往上的(类似windows的开始菜单一样)。不知道你有没有时间,告诉我应该修改哪个地方?
tks again
“现在本博客的 RSS feed 列表也是这样实现的. ”
最好加一个小箭头,提示有列表
请使用.stop()