jQuery – 鼠标经过(hover)事件的延时处理

这篇文章发布于 2010年07月1日,星期四,21:24,归类于 jQuery相关。 阅读 250743 次, 今日 4 次 33 条评论

 

一、关于鼠标hover事件及延时

鼠标经过事件为web页面上非常常见的事件之一。简单的hover可以用CSS :hover伪类实现,复杂点的用js。

一般情况下,我们是不对鼠标hover事件进行延时处理。但是,有时候,为了避免不必要的干扰,常会对鼠标hover事件进行延时处理。所谓干扰,就是当用户鼠标不经意划过摸个链接,选项卡,或是其他区域时,本没有显示隐藏层,或是选项卡切换,但是由于这些元素上绑定了hover事件(或是mouseover事件),且无延时,这些时间就会立即触发,反而会对用户进行干扰。

例如,在腾讯网首页,几乎对所有的鼠标经过事件进行了延时处理,例如其选项卡:
腾讯首页选项卡 张鑫旭-鑫空间-鑫生活

或是其顶部的搜搜导航条,见下图:
腾讯网首页搜搜搜索栏 张鑫旭-鑫空间-鑫生活

二、实例及演示

本文的主要内容就是展示我前几天写的鼠标延迟的方法,jQuery下的方法,水平拙劣,仅供参考。本文就以腾讯网首页搜搜搜索栏的一些鼠标经过效果为实例,演示jQuery下的延时处理。下图为demo页面的效果截图:
jQuery鼠标延迟demo截图 张鑫旭-鑫空间-鑫生活

您可以狠狠地点击这里:腾讯搜搜搜索框延迟demo

三、代码与实现

说到延时,离不开window下的setTimeout方法,本实例的jQuery方法的核心也是setTimeout。代码不长,完整如下:

(function($){
    $.fn.hoverDelay = function(options){
        var defaults = {
            hoverDuring: 200,
            outDuring: 200,
            hoverEvent: function(){
                $.noop();
            },
            outEvent: function(){
                $.noop();    
            }
        };
        var sets = $.extend(defaults,options || {});
        var hoverTimer, outTimer;
        return $(this).each(function(){
            $(this).hover(function(){
                clearTimeout(outTimer);
                hoverTimer = setTimeout(sets.hoverEvent, sets.hoverDuring);
            },function(){
                clearTimeout(hoverTimer);
                outTimer = setTimeout(sets.outEvent, sets.outDuring);
            });    
        });
    }      
})(jQuery);

这段代码的目的在于让鼠标经过事件和延时分离的出来,延时以及延迟的清除都已经由此方法解决了。您所要做的,就是设定延时的时间大小,以及相应的鼠标经过或是移除事件即可。举个简单的例子吧,如下代码:

$("#test").hoverDelay({
    hoverEvent: function(){
        alert("经过我!");
    }
});

表示的含义是id"test"的元素在鼠标经过后200毫秒后弹出含有“经过我!”文字字样的弹出框。

关于此js,您可以狠狠地点击这里:jquery.hoverdelay.js(725字节)

ok,现在应用到本文的实例上。

腾讯网的首页的搜索框上面除了鼠标经过延时,其换肤也是值得一提的,关于换肤我之前也提过,在jQuery-马化腾产品设计与用户体验的一些技术实现一文中,相应的demo页面您可以狠狠地点击这里:腾讯首页个性化换肤demo页面

首先,展示下腾讯首页搜索栏的主要HTML结构域代码:

<div id="sosoFod">
    <h3 id="sosoweb" class="s1">网页</h3>
    <h3 id="sosoimg" class="s2">图片</h3>
    <h3 id="sosovid" class="s2">视频</h3>
    <h3 id="sosomus" class="s2">音乐</h3>
    <h3 id="sososoba" class="s2">搜吧</h3>
    <h3 id="sosowenwen" class="s2">问问</h3>
    <h3 id="sosoqz" class="s2">博客</h3>
    <h3 style="cursor:pointer;" class="s2">更多▼
        <div style="display:none;" class="more" id="tm">
          <ul>
            <li><a href="#">综合</a></li>
            <li><a href="#">新闻</a></li>  
            <li><a href="#">词典</a></li>
            <li><a href="#">生活</a></li>
            <li><a href="#">百科</a></li>
            <li style="border-top:1px solid rgb(178, 208, 234);"><a href="#">所有产品</a></li>
          </ul>
       </div>
    </h3>
</div>

与先首页代码几乎一致,如假包换。应用了本文没什么技术含量的延迟方法后,可以应用如下的代码实现延迟执行。

$(".s2").each(function(){
$("#sosoFod h3").each(function(){
    var that = $(this);
    var id = that.attr("id");
    if(id){
        that.hoverDelay({
            hoverEvent: function(){
                $(".s1").attr("class","s2");
                that.attr("class","s1"); //感谢“type23”提供了绑定对象方法
                $(this).attr("class","s1"); 
            }        
        });
    }else{
        that.hoverDelay({
            outDuring: 1000,
            hoverEvent: function(){
                $("#tm").show();        
            },
            outEvent: function(){
                $("#tm").hide();
            }
        });
    }
});

唉,惭愧,代码就这样,没什么技术含量的,希望对有用的有用吧。“更多”的下拉鼠标移出后1000毫秒后下拉框隐藏。

基本上都是代码在撑页面,说点有用的东西吧。
hoverDelay方法共四个参数,表示意思如下:

hoverDuring
鼠标经过的延时时间
outDuring
鼠标移出的延时时间
hoverEvent
鼠标经过执行的方法
outEvent
鼠标移出执行的方法

四、我嚓,结语

月光大人曾说过与下面主要意思一样的话:写博客三五天写一篇重量级的文章,隔个一天两天写个简单,价值度偏低的文章,是比较不错滴。本文就属于有凑篇数之嫌的价值相对偏低的文章。加上本身js还很稚嫩,所以本文内容的方法一般般,仅供参考。

对了,我是抱有疑问的,如何在写jQuery插件组件这类公共方法时将当前对象传到设置的默认的方法中。例如本实例中,如果将当前$(this)对象传到hoverEvent或是outEvent方法中呢,希望有高人不吝赐教。

(本篇完)

分享到:


发表评论(目前33 条评论)

  1. $(this)失效!!!!!!!!!!!说道:

    $(“#test”).hoverDelay({
    hoverEvent: function(){
    alert(“经过我!”);
    $(this)失效!!!!!!!!!!!
    }
    });

  2. Eleven说道:

    鼠标放在更多上,从更多移到子菜单上这期间,子菜单要一直显示;
    但是在更多和子菜单之间移动时,子菜单会消失;
    有一个解决办法是把更多的元素区域高度加长,这样更多的作用域会到子菜单,但是这种办法不能用,请问还有别的解决办法吗?

  3. 小手说道:

    hoverTimer = setTimeout(sets.hoverEvent, sets.hoverDuring);你确定这样写,定时器里面的那个sets.hoverEvent会执行!!!

  4. sinsay说道:

    这段代码的 bug 还挺不少,包括 this 指针的处理, timer 的作用域等等。。。

  5. en说道:

    分享一个 web(互联网)开发学习交流群;301909232,欢迎大家踊跃参与,网页设计,php、linux,等等;请收到的,继续传下去,谢谢

  6. 流星说道:

    假如是是用onclik 那该怎么写呢?因为最近刚刚学JS,所以还不是很懂耶,谢谢啦
    为什么要用onclik呢
    1、用户也许根本不懂这导航是点击还是滑动的,假如他的思维就是按照按键触发才可以实现,那么200微秒,似乎有点反应迟钝;
    2、假如把时间调到快一点的话,就会像你开头说的一样,对用户造成干扰

  7. hunter说道:

    this 参数传递错误,
    $(this).hover(function(){
    clearTimeout(outTimer);
    that = this;
    hoverTimer = setTimeout(function(){sets.hoverEvent.apply(that)}, sets.hoverDuring);
    },function(){
    clearTimeout(hoverTimer);
    that = this;
    outTimer = setTimeout(function(){sets.outEvent.apply(that)}, sets.outDuring);
    });

    应该把that复制提到函数里面,我是针对里面的js评价的。。

  8. Alice说道:

    弱弱的问一下
    18楼的 sets.hoverEvent.apply(that)
    和22楼的sets.hoverEvent.apply(that)
    怎么理解啊,这里的that不是指向当前触发Jquery对象吗?

  9. 小白学JS说道:

    为什么把“更多”下面的子块复制到其他项目下就不行了呢。。。

  10. jiahao说道:

    //修改绑定live事件
    $.fn.hoverDelay = function(options) {
    var defaults = {
    hoverDuring: 200,
    outDuring: 200,
    hoverEvent: $.noop,
    outEvent: $.noop
    };
    var sets = $.extend(defaults, options || {});
    return $(this).live(“hover”,function(event) {
    var that = this;
    if(event.type == “mouseenter”){
    clearTimeout(that.outTimer);
    that.hoverTimer = setTimeout(
    function(){sets.hoverEvent.apply(that)},
    sets.hoverDuring
    );
    }else {
    clearTimeout(that.hoverTimer);
    that.outTimer = setTimeout(
    function(){sets.outEvent.apply(that)},
    sets.outDuring
    );
    }
    });
    }

  11. 未命名说道:

    太感谢了,真的很好用,没有这个JS的话真的会浪费很多流量,会多很多次请求,现在我用了这个0.5秒鼠标移动才求请,减清了服务器压力,非常不错。。谢谢

  12. 小西说道:

    这个很好用!

  13. cinron说道:

    插件一如既往的好
    to:麦子 的确有时候不能正常关闭,你的解决办法帮了我大忙了,谢谢

  14. 麦子说道:

    感谢楼主,做一个菜单时发现发现,有时移到相邻的项时,之前展开的子项没有关闭。
    把var hoverTimer, outTimer; 放在更下一层的闭包函数可以解决。

    return $(this).each(function(){
    var that = this;
    var hoverTimer, outTimer;
    $(this).hover(
    function(){
    clearTimeout(outTimer);
    hoverTimer = setTimeout(
    function(){sets.hoverEvent.apply(that)},
    sets.hoverDuring
    );
    },

    function(){
    clearTimeout(hoverTimer);
    outTimer = setTimeout(
    function(){sets.outEvent.apply(that)},
    sets.outDuring
    );
    }
    );
    });

  15. zxk说道:

    非常感谢,你帮了我大忙

  16. 阿冰说道:

    你好,我新插入的html结构 ,无法使用激活事件,怎么把live()加入呢?QQ314724012

  17. 星野天河说道:

    多谢,目前用了这个效果.
    关于this的传递问题我解决了,参数也简化了一下.
    $.fn.hoverDelay = function(hoverEvent, outEvent){
    var hoverTimer, outTimer;
    return $(this).each(function(){
    $(this).hover(function(){
    var t = this;
    clearTimeout(outTimer);
    hoverTimer = setTimeout(function (){
    hoverEvent.call(t);
    }, 200);
    },function(){
    var t = this;
    clearTimeout(hoverTimer);
    outTimer = setTimeout(function (){
    outEvent.call(t);
    }, 200);
    });
    });
    }

  18. 糖饼说道:

    (function($){
    $.fn.hoverDelay = function(options){
    var defaults = {
    hoverDuring: 200,
    outDuring: 200,
    //hoverEvent: function(){
    // $.noop();
    //},
    hoverEvent: $.noop,
    //outEvent: function(){
    // $.noop();
    //}
    outEvent: $.noop
    };
    var sets = $.extend(defaults,options || {});
    var hoverTimer, outTimer;
    //return $(this).each(function(){
    return $(this).hover(function(){
    clearTimeout(outTimer);
    hoverTimer = setTimeout(sets.hoverEvent, sets.hoverDuring);
    },function(){
    clearTimeout(hoverTimer);
    outTimer = setTimeout(sets.outEvent, sets.outDuring);
    });
    //});
    }
    })(jQuery);

  19. 下一站说道:

    看了好多博主的文章。非常喜欢。我提一点个人看法,供参考:
    hoverDelay现在只接收一个动作参数,可以把动作的所有者也用有参数传进去。

  20. crossyou说道:

    实际用到了,就有用了。
    感谢分享。

  21. 康康说道:

    问题解决了,我在li标签里加了个和子元素同级的透明a标签盖住了下面的li,然后鼠标放到导航上的话其实是放在了a标签上,于是导航就可以点击了。
    但是我不明白的是,假如a的hover事件是通过继承li的hover来完成显示子菜单的话,那为什么a的click事件没有继承li呢?也许讨论这个根本没有用,但是如果您知道的话还请不吝赐教咯。
    很感激你能这么耐心的看我问题,没有你就没有这个导航的现在,谢谢!

    • 张 鑫旭说道:

      jQuery的hover方法是有别于mouseover与mouseout方法,例如,鼠标移动到div内部的一个的图片上,如果是使用mouseover与mouseout方法,当鼠标“悬停”在图片上时会触发mouseout事件,这是不合理的。而jQuery的hover方法则修正了这个问题。mouseover以及mouseout方法似乎更符合您的“事件继承”的理解,而hover不然。

  22. 康康说道:

    http://2009.jqdd.com/yytest/
    想要的结果是:点击导航也可以链接到其它页面。
    因为a标签下放一个div不符合嵌套规则而且会导致很多问题,所以我在尝试了很多次之后只能无奈的用li标签做了导航,当鼠标放到品牌专区的时候可以显示下方的区域,但是怎么给导航加链接让我很纠结。
    我先试着给li加了onclick事件,结果他包裹的子元素全部都执行了这个事件,如果我把子元素的onclick事件return false,又导致点击子元素的链接没有反应.

  23. 康康说道:

    我这里发现了一个问题,就是:如果“更多”这个按钮需要添加一个指向的话,这样的结构好像很难做到,可是如果把“更多”按钮下包含的块移出来,鼠标离开“更多”按钮的话又会触发mouseout事件…
    怎么样才能在“更多”按钮上添加一个onclick事件呢?

  24. type23说道:

    在函数外围:var self = this;
    然后改这句:
    hoverTimer = setTimeout(function(){sets.hoverEvent.apply(this, [$(self)])}, sets.hoverDuring);

    apply的第一个参数是this还是self你自己决定。

  25. 康康说道:

    对不起,我只是怕说不明白,我没那么迂腐,只是不善于沟通。
    那个js文件我借用了,谢谢啊!

  26. 康康说道:

    $(“.s2”).each(function(){
    var that = $(this);
    var id = that.attr(“id”);
    if(id){
    这里有一个问题需要探讨一下,还有一个问题需要请教一下:
    1. 虽然我依然看不懂jquery.hoverdelay.js这个文件,不过在测试的时候发现第一个项【网页】在取消激活之后,无论鼠标如何hover都无法再次激活了。
    然后我逼迫自己去一行一行的看代码,在我所引用的这段代码中,第一行的意思应该是将class=”s2″的元素遍历并赋予hover事件…吧~,但在这个时候页面的第一个项【网页】的class=”s1″,所以没有被XX。
    我觉得应该可以这样解决:$(“#sosoFod h3”).each(function(){ … }

    2.为什么我不那么确定说可以这样解决,而加了“应该可以”,是因为我还有一个问题需要请教*^^*
    第二行:var that = $(this);
    ①这里的this指的是当前调用hover事件的标签h3么?
    ②然后 var id… 这句就是把当前h3标签的id值取到对吧?
    ③最后 根据是否有id值执行相应的函数是吗?
    我不大确定,所以如果您没有太多时间的话,就请只用回答“1.是2.对3.嗯”就可以了,如果错了就请尽量解释下吧。

  27. 康康说道:

    更惭愧,这么简单都看不懂,希望上午能自己用这个js做个菜单出来。
    唉,其实做出来了又能怎么样呢~
    还是不会…