首页 > 技术文章 > javascript父级鼠标移入移出事件中的子集影响父级的处理方法

zhanyishu 原文

一、我们先分析其产生的原因:

1、当鼠标从父级移入子集时触发了父级的两个事件:a、父级的mouseout事件(父级离开到子集);b、由于事件冒泡影响,又触发了父级的mouseover事件(父级移入父级);

2、当鼠标从子集移出到父级时又触发了父级的两个事件:a、由于事件冒泡影响,父级触发了mouseout事件(父级移出父级);b、再触发了父级的mouseover事件(子集移入父级)

注:红色字体的解释是事件冒泡的奇妙之处。

二、解决方法:

首先必须先熟悉以下两个方法和一个事件属性:

a,b为节点

1、a.contains(b)

如果a包含b,返回true;否则返回false;a包含a同样返回true(不兼容火狐)

2、 a.compareDocumentPosition(b) 兼容火狐

这玩意就好玩了:

a在b之后返回2;

a在b之前返回4;

a被b包含返回8;

a包含b返回16;

a包含a返回0;

3、ev.relatedTarget 

返回事件的目标节点相关的节点;

对于 mouseover 事件来说,该属性是鼠标指针移到目标节点上时所离开的那个节点。

对于 mouseout 事件来说,该属性是离开目标时,鼠标指针进入的节点。(IE9以下不兼容)

但IE7/8下有ev.toElement和ev.fromElement;

mouseover事件对应ev.fromElement

mouseout事件对应ev.toElement

接下来开始解决问题:

假设a是父级;b是与事件关联的节点:

解决原因1:

方法(1)a包含b返回true,a包含a返回true;

方法(2)a移出b(mouseout)返回4+16即返回20;a移入a(mouseover)返回0;

解决原因2:

方法(1)a包含a返回true,a包含b返回true

方法(2)a移出a返回0,b移入a返回4+16即返回20;

要让以上都不执行:

见代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>解决子集影响父级事件</title>
    <style type="text/css">
    body  {  100%; height: 100%; padding: 0; margin: 0;}
    #div1 {  200px; height: 200px; background: red; }
    #div2 {  100px; height: 100px; background: blue;position: absolute; top: 50px; left: 50px;}
    #txt {  800px; background: lime; color: red; height: 50px; line-height: 50px; font-size: 30px}
    </style>
    <script>
    window.onload=function(){

        var oTxt = document.getElementById('txt');
        var a = document.getElementById('div1');
        var b = document.getElementById('div2');

        alert(b)
        a.onmouseover=function(ev){            
            var oEvent = ev || window.event;
                            
            if(toAffect(a,oEvent,'mouseover')){
                oTxt.value += "移入"+" ";
            }
        
        }
        a.onmouseout=function(ev){        
            var oEvent = ev || window.event;
            if(toAffect(a,oEvent,'mouseout')){
                oTxt.value += "移出"+" ";
            }

        }
    }

    
    function toAffect(obj1,ev,event){
        var obj2 = null;
        if(ev.relatedTarget){
            obj2 = ev.relatedTarget;
        }
        else{
            if(event == 'mouseover'){
                obj2 = ev.fromElement;
            }
            else if(event == 'mouseout'){
                obj2 = ev.toElement;
            }
        }
        if(obj1.contains){
            return !obj1.contains(obj2);
        }
        else{
            return !!(obj1.compareDocumentPosition(obj2)-20)&&a!=b;
        }
    }
    </script>
</head>
<body>
    <div id="div1">
        父级
        <div id="div2">子集</div>
    </div>
    <input id="txt" type="text" />
</body>
</html>

    代码中的toAffect方法便是解决子集影响父级的方法。

推荐阅读