jQuery 的 slideUp 和 slideDown 动画

Dec 13th, 2009 Add Comment

jQuery 可以通过调用 animate 方法添加动画效果, 而且还提供了一套别名, 使用起来很是方便. 其中 slideDownslideUp 两方法的作用是纵向展开和卷起一个页面元素, 被使用的几率很高, 却一直存在一个小问题.

如果目标元素是被外部事件驱动, 当鼠标快速地连续触发外部元素事件, 动画会滞后的反复执行, 相当不美观 (演示页面). 演示页面中有一个按钮, 请用鼠标迅速地来回划过...

不知道本博客的老读者是否记得我写过的一个关于菜单导航的专题, 其中一节讨论的是滚动导航菜单的实现方法 (演示页面), 实现了类似 slideUp 和 slideDown 的效果, 但是不存在上述问题, 因为它的滚动高度是即时计算的, 而 jQuery 作为一个通用框架应用的面很广, 很难做到这一点.

如果用 jQuery 来实现这样的效果, 该如何处理呢?
其实很简单, 只需在触发元素上的事件设置为延迟处理, 即可避免滞后反复执行的问题. 例如: 当鼠标滑过按钮后 0.2 秒, 菜单才会展开, 如果鼠标离开按钮, 展开的处理将被终止. 也就是说, 想要展开菜单鼠标必须有 0.2 秒的事件停留在按钮上, 那么迅速地划过按钮是无法执行展开事件的. 卷起也是如此.

下面我们用代码来解决这个问题.

// 线程 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 列表也是这样实现的.

最后, 拓展一下思维. 不知道你是否见过网页上有这样的效果: 当鼠标在某个元素上停顿一定的时候后页面上某些内容会被激活. 这样的效果处理方法和上面说到的其实是大同小异, 有兴趣的同学可自行尝试.

声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: jQuery 的 slideUp 和 slideDown 动画

  1. http://0.gravatar.com/avatar/257a27cb26eb4d3bb7055ad3e6af4bd6?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    看不是很懂

  2. http://0.gravatar.com/avatar/ae5a1c9d23918abe26077096e790713a?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    其实用.queue()就能解决了,不用这么麻烦

  3. http://1.gravatar.com/avatar/77470e01c97c5ae9c9055ec14a89dcf5?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我之前也遇到这样的一个问题,不过加个stop()可以清除重复滑动的效果。
    我写的代码是这样的:
    $('.mainlevel').hover(function(){
    $(this).find('ul').stop(true,true).slideDown(320);
    },function(){
    $(this).find('ul').stop(true,true).slideUp(200);
    });

  4. http://1.gravatar.com/avatar/1d1592e57e5587946eb6c4c221a3801c?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    貌似使用 show("slow") 比 slideDown 效果好。

  5. http://1.gravatar.com/avatar/3c04f7bb29698af5e4f5340616c5f990?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    stop加参数

  6. http://0.gravatar.com/avatar/6a2a40797fa5fd376dade3695d2bd57e?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    请使用.stop()

  7. http://1.gravatar.com/avatar/bb6eeca6c19f5f11c8aaaa061ccde5e7?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    “现在本博客的 RSS feed 列表也是这样实现的. ”
    最好加一个小箭头,提示有列表

  8. http://1.gravatar.com/avatar/3058a751f7e9ce3189beee2dd04a549b?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    嗨 mg12 谢谢你写了这么详细的教程。我学到很多东西。:)

    我想修改一下滑动方向的时候,却不知道怎么下手。你能帮我一下吗?

    我想把下滑的动作slideDown,改成往上滑。因为我的导航bar是在页面最下面,我想滑出的菜单是往上的(类似windows的开始菜单一样)。不知道你有没有时间,告诉我应该修改哪个地方?

    tks again

  9. http://0.gravatar.com/avatar/c793a51cb3aa531de41b5e5ef177867d?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    这个解决方法不错,记得以前在cssrain的网站上面好像也看到了一个解决方法,原理都是延迟。

  10. http://0.gravatar.com/avatar/490cf262668eebb0f0f1a50d9d48d702?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    @Xu.hel
    我明年一定要去成都玩一次. 你备钱请客吧, 哈~

    @sky
    如果把悬停时间设置比动画时间稍长就不会发生这个问题了.

    @underone
    好玩不?

    @Justice
    哦~ 这个很好, 我要细细得看一遍, 谢谢哈~

    @bolo
    我敲错日期了, 改了一下都被你看到了...

    @Gaze , @Kael
    嗯, 很好. 我又学到一招了.

  11. http://1.gravatar.com/avatar/9d7a1fd054cb532d3daac3b19aa70ed3?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我的RSS订阅是加一个判断 is(":animated") 来阻止再触发

  12. http://1.gravatar.com/avatar/b01f89ff5c36ab53090666fe5b1afe5d?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    细节的问题也要很讲究~~

  13. http://0.gravatar.com/avatar/e7cd768b796a268f6802455b4d1e4afa?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    jQuery的hover事件,没有判断event的relatedtarget,所以在悬停的时候,在hover中定义的方法会不断地被执行。

    可以判断鼠标的来源(relatedtarget),已经触发过hover,就可以不再触发,这也是这个问题更好的解决方法。可以参考一下mootools的mouseenter的定义。

    延时仍然不是根本的解决方法,如果动画时间较长,这个问题仍然会重演。

  14. http://0.gravatar.com/avatar/45da219c4cd65d34c0fcf2cb9ac5bd85?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    如18楼所说. 真的好巧. 偶也是刚好看到这篇. 只要加上 stop(true, false) 即可解决.
    http://css-tricks.com/examples/jQueryStop/
    但延迟执行的处理其它时候也可能会用到

  15. http://0.gravatar.com/avatar/2a9c4f525050372a6fe0b10ce4fe8957?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    新文章跳票了?

  16. http://1.gravatar.com/avatar/1cfd6b67e61a959b431aa1bc3e4f6736?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    好巧,今天看到 CSSTricks 上也写了篇关于这个问题的。他的解决方法好像相当简单啊。
    http://css-tricks.com/full-jquery-animations/

  17. http://1.gravatar.com/avatar/58be12971823af5c6520597bd6d3a552?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    围观一下~~·看的不是太懂。。

  18. http://1.gravatar.com/avatar/78b0fd25b4aadfa50d9dde0ba2cc5d50?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    围观技术贴…

  19. http://1.gravatar.com/avatar/9d9477ecc62b02e1462344209df591c6?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    好东西 收藏一下

  20. http://0.gravatar.com/avatar/e8f87528ed0a0eaba60009f8580df401?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我在6.3的按钮上玩了半天:)~

  21. http://0.gravatar.com/avatar/28d2a9b4a4f0c1b2e17d11e98bc57612?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    这里聚集了这么多搞前台的?

  22. http://1.gravatar.com/avatar/bb05acb5b9b70b8886b356d190d3bb4a?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    已经算很完美的解决方案了。

  23. http://1.gravatar.com/avatar/9c1ffe4dff0c8b6a4c99f62e075c98e7?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    没根本解决。移动鼠标如果能掌握那个0.2秒的规律还是存在这个问题. 不过一般客户不会这样。呵呵

  24. http://0.gravatar.com/avatar/c1834913e0459af48c2bcb63a641b223?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    这个我一直有疑问来着,现在总算有解决方法了

  25. http://0.gravatar.com/avatar/e7eb964007e8bd7c5048761b77382bf7?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    谢谢咯,呵呵.有机会来成都耍哈

  26. http://1.gravatar.com/avatar/fc14132aa59f391e31a384177bea605b?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    前排圍觀~~~

  27. http://0.gravatar.com/avatar/c3bbb9ae30a86d6adbb98f71874a0b07?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    click事件还是不好处理……

  28. http://1.gravatar.com/avatar/d4efbdaa43e9202a96df023ae758a9bf?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我做滑动展开feed订阅时就是这么做的,我设置了100毫秒(貌似太短了,回头加长点吧),想一块去了。。 :razz: 第一次感觉离大师如此近。。。

  29. http://1.gravatar.com/avatar/fa7f6e086d0164f7a5c41a79df6bd3ee?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    做个 小 板凳 学习下。

  30. http://0.gravatar.com/avatar/2a9c4f525050372a6fe0b10ce4fe8957?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我以前发给你那个jQuery插件也是实现mouseover事件延迟的,扩展性强些,如果页面上大量应用了这些动画效果的话可以挂上那个插件。

    另外你写的这段代码可以改写成两个函数,方便多次调用啊

  31. http://1.gravatar.com/avatar/185566d86aa5298094753cc66a77dfea?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    这个Demo似曾相识,锋利的jQuery里?忘了

  32. http://0.gravatar.com/avatar/e9e03e27bace17f0b8f333df850efbab?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G
  33. http://0.gravatar.com/avatar/86bec4c86b55b9192d38bcab93e4f30a?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G
  1. Loading...