javascript中mouseover和mouseout事件详解

原文链接:http://blog.sina.com.cn/s/blog_468530a60101awlw.html

  与 mouseenter 事件不同,不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件。只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。
  与 mouseout 事件不同,只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。如果鼠标指针离开任何子元素,同样会触发 mouseout 事件。

  解决两者的区别,看下面引用的例子:

  当为某个容器绑定了 onmouseover 或者onmouseout 事件时,如果这个容器中有其它元素节点,那么鼠标在内部移动时会频繁触发 onmouseover和onmouseout 事件。

  而我想要的效果是:事件仅在鼠标进入/离开元素区域触发一次,当鼠标在元素区域内部移动的时候不会触发。

  为什么会出现这个原因呢?其实是因为事件冒泡导致的。当鼠标移上或者移出容器中的子节点时,会分别触发mouseover和mouseout事件,紧随着dom树向上冒泡传递,直到被事件处理程序(监听器)捕获捕获或者冒泡到根节点(document或者window),也就是说事件会向它的父级对象派发。

  知道了问题产生原因,那么解决起来是不是也很简单呢?最初我想的是取消事件冒泡,使用event.cancelBubble = true(IE)和e.stopPropagation()(其它浏览器),但是简单测试后发现貌似没有什么效果,问题依旧,貌似冒泡停止不了,原因不明。(补充:我是测试将容器中的a链接节点取消冒泡,但是发现鼠标移上移下还会触发事件。a节点下还有span节点。难道要将容器中所有节点都取消冒泡才行?有心人可以测试,如果真的这样,那也太恶心了,要是N多的节点,难道都要停止冒泡下?)

  其实在IE下鼠标事件有个 mouseEnter 和 mouseLeave,这个就是移进和移处容器时触发一次,在内部移动则不会触发,遗憾的是只有IE支持。我们现在要做的就是“为非IE浏览器添加mouseEnter和mouseLeave支持”。

  我翻阅了百度最新开源的JS库tangram,看了里面的处理,发现貌似是单独处理了非IE浏览器下的事件,使用一个叫“baidu.event._eventFilter._crossElementBoundary(listener, e)”的方法修正mouseover和mouseout,然后封装了个mouseEnter和mouseLeave事件。

baidu.event._eventFilter._crossElementBoundary = function(listener, e){
    var related = e.relatedTarget,
        current = e.currentTarget;
    if(typeof related == 'undefined'){
        return listener.call(current, e);
      }
    // 如果current和related都是body,contains函数会返回false
    // Firefox有时会把XUL元素作为relatedTarget
    // 这些元素不能访问parentNode属性
    // thanks jquery & mootools
    //如果current包含related,说明没有经过current的边界
    //注:baidu.dom.contains是个定义的检测节点是否包含的函数,下面我会讲到
    if(related === false || current == related || related.prefix == 'xul' || baidu.dom.contains(current, related)){
         return ;
      }
    //调用执行
    return listener.call(current, e);
    };

  百度的方法我并不喜欢,首先它只对非IE浏览器进行了处理,当然,它又进行了封装,可以直接使用mouseEnter和mouseLeave;但是,我们做普通开发,没必要这么封装,我只是想要简单的去掉mouseover和mouseout的这个恼人特性。

  而jQuery则不是这么做的,它是直接对IE和其它所有浏览器下的mouseover和mouseout事件进行了修正。参考jQuery,我得到了我目前所有的代码。

  首先,介绍个判断节点对象是否包含的函数contains.

function contains(p,c){
    return p.contains ?
    p != c && p.contains(c) : !!(p.compareDocumentPosition(c) & 16);
}

  然后就是重点的了,这里我们在IE下用到了fromElement和toElement,这两个是IE下的鼠标移上去时和移出时的节点对象。

function fixedMouse(e,target){
    var related,
    type=e.type.toLowerCase();//这里获取事件名字
    if(type=='mouseover'){
        related=e.relatedTarget||e.fromElement
      }else if(type='mouseout'){
        related=e.relatedTarget||e.toElement
      }else return true;
      return related && related.prefix!='xul' && !contains(target,related) && related!==target;
}

  然后我们怎么用呢?比如在绑定事件时,

//addListener为封装的事件绑定函数
addListener(target,'mouseover',function(e){
    e=e||window.event;
    if(fixedMouse(e, target)){
    //do something
    }
},false);

  这样就会只在移入移出target节点时触发mouseover和mouseout了。

  当然,你也可以将上面的代码单独封装成mouseEnter和mouseLeave,这样可以以后调用时更好区别mouseover和mouseout。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值