zoukankan      html  css  js  c++  java
  • js mouseover mouseout 多次触发

    问题:当鼠标移动到元素上,多次触发mouseover,mouseout事件。

    (注,该问题是在实现鼠标移动到一起菜单,滑动弹出二级时碰到的;因为鼠标移动到二级菜单时,动画再次触发,才意识到该问题;之前因为使用的是:hover伪类实现的显示二级菜单,并且没有加入动画,所以并没有发现该问题。)

    问题原因分析:事件的冒泡机制,当子元素上发生相应事件时,会触发父级元素的该事件。如A元素包含B元素,在A,B元素上分别添加mouseover,mouseout监听事件,当鼠标移到A上,但不在B上时,触发A的mouseover,同时对应的event.eventPhase为2即目标阶段;当鼠标继续移入B元素中时,这时触发A事件的mouseout,event.eventPhase为3,即冒泡阶段,同时触发B事件的mouseover,event.eventPhase为2,即目标阶段。

    解决方法:检测事件的相关元素(relatedTarget,对于mouseover来说:relatedTarget是鼠标进入元素前,所离开的元素;对于mouseout,relatedTarget是鼠标离开元素后,所进入的元素)是被绑定元素的子元素与否。(或者利用jQuery的mouseenter,mouseleave事件,因为jquery已经将该事件封装)

    function contains(parentNode, childNode) {
        if (parentNode.contains) {
            return parentNode != childNode && parentNode.contains(childNode);
        } else {
            return !!(parentNode.compareDocumentPosition(childNode) & 16);
        }
    }

    该函数是判断两个节点的关系,它考虑到IE与其他浏览器的兼容性,[dom].contains([dom])方法是IE浏览器的方法([dom]表示文档流中的节点),[A].compareDocumentPosition([B])是DOM3中的方法,下面是不同位置关系对应的返回结果。

     Bits          Number        Meaning
    000000         0              元素一致
    000001         1              节点在不同的文档(或者一个在文档之外)
    000010         2              节点 B 在节点 A 之前
    000100         4              节点 A 在节点 B 之前
    001000         8              节点 B 包含节点 A
    010000         16             节点 A 包含节点 B
    100000         32             浏览器的私有使用

    接下来是判断事件相关元素与目标元素之间的关系,只有当触发事件的相关元素不是目标元素的后继节点,checkHover()函数才返回true.

    function checkHover(e,target){
        if (getEvent(e).type=="mouseover")  {
            return !contains(target,getEvent(e).relatedTarget||getEvent(e).fromElement) && !((getEvent(e).relatedTarget||getEvent(e).fromElement)===target);
        } else {
            return !contains(target,getEvent(e).relatedTarget||getEvent(e).toElement) && !((getEvent(e).relatedTarget||getEvent(e).toElement)===target);
        }
    }

     

    getEvent是为了兼容IE浏览器;checkHover函数中之所以添加一个if判断是因为IE下mouseover和mouseout的相关元素分别对应的是fromElement,toElement,因此分别处理,当是其他事件时,这两个属性在IE下为null。而FF和chrome浏览器中的相关元素都是relatedTarget,mouseover中relatedTarget是鼠标移到目标元素时所离开的那个元素,mouseout中relatedTarget是鼠标离开目标元素时要进入的元素,对于其他事件该属性无用。

    最后是函数的调用。

    myElement.onmouseover=function(e){
        if(checkHover(e,this)){
            do someting...
        }
    }

     附加:

    1)event还有两个对象currentTarget,target;currentTarget是当前响应事件的对象,target是最初触发该事件的对象;

    2)阻止事件的冒泡为event.stopPropagation();

    3)阻止默认行为为event.perventDefault();

    4)在处理函数中最后写上return false;即阻止冒泡又阻止默认操作。

    5)事件分为3个阶段:捕捉阶段,eventPhase为1;目标阶段,eventPhase为2;冒泡阶段,eventPhase为3。

    下面为测试时,监控程序的代码

    var count=0;
    $(this).bind('mouseover',function(e){
            console.log(++count+' mouseover: '+e.target.className+" "+e.eventPhase);
            ...
        
    }).bind('mouseout',function(e){
            console.log(++count+' mouseout: '+e.target.className+" "+e.eventPhase);
            ...
    })
  • 相关阅读:
    17.10.13
    17.10.12
    17.10.11
    17.10.10
    17.10.05
    17.10.04
    17.10.03
    17.10.02
    17.10.01
    17.9.29
  • 原文地址:https://www.cnblogs.com/hugh2006/p/3637131.html
Copyright © 2011-2022 走看看