>  기사  >  웹 프론트엔드  >  JavaScript에서 마우스 오버 및 마우스 아웃의 다중 트리거에 대한 솔루션

JavaScript에서 마우스 오버 및 마우스 아웃의 다중 트리거에 대한 솔루션

黄舟
黄舟원래의
2017-03-01 14:58:381099검색

문제 설명

마우스가 id1로 이동하면 id2가 표시되고, id1을 벗어나면 id2가 표시되기를 바랍니다. 문제는 다음과 같습니다.
1. id1에서 id2로 마우스를 이동하면 ID가 표시됨에서 표시되지 않음으로 변경됩니다.
2. id2에서 id1로 마우스를 이동하면 id2가 표시됩니다. 표시되다가 표시되지 않다가 표시되다가
id1이나 id2에 마우스가 움직일 때 항상 id2가 변하지 않고 표시되기를 바라는 것입니다.

<script type="text/javascript" src=" 
</script><p id="id1" style="width:800px; height:400px; background-color:#F23">
        <p id="id2" style="width:400px; height:300px; background-color:#0F8; display:none;">
        </p>
    </p><script type="text/javascript">
    $("#id1").mouseover(function(){
                $(this).children().fadeIn(1000);
            }).mouseout(function(){
                $(this).children().fadeOut(1000);
            });</script>

JavaScript에서 마우스 오버 및 마우스 아웃의 다중 트리거에 대한 솔루션

문제 해결

초기 문제 분석, 마우스가 id1에서 id2로 이동할 때, 마우스가 id2에서 나가서 id1로 들어가기 때문에 마우스아웃이 발생합니다. 이벤트는 id1에 대해 트리거되므로 id2는 표시되지만 표시되지 않습니다. 그런 다음 마우스가 id2로 이동하면 버블링 메커니즘으로 인해 id2에 대한 마우스 오버가 id1에 대한 마우스 오버 이벤트가 발생합니다. 트리거되고 id2가 표시되지 않음에서 표시됨으로 변경됩니다. 같은 방식으로 마우스가 id2에서 id1로 이동하면 id2에 대해 mouseout 이벤트가 발생합니다. 또는 버블링 메커니즘으로 인해 mouseout 이벤트가 id1로 전송되고 id2가 표시됨에서 표시되지 않음으로 변경된 후 마우스가 이동합니다. 이전에는 마우스 오버 이벤트가 발생한 후 id2가 표시되지 않음에서 표시됨으로 변경되었습니다.

위 문제의 궁극적인 해결책은 마우스가 id1에서 id2로 이동할 때 id1의 mouseout 이벤트를 방지하는 것 같습니다. id2에서 mouseout 이벤트가 버블링되는 것을 방지합니다. id1. 그러면 단순히 버블링을 방지하는 것만으로는 문제가 해결되지 않습니다.

이 문제를 해결하기 위해 Jquery에서는 mouseenter 및 mouseleave 메서드를 제공합니다. 그래서 JS 코드를 다음과 같이 변경했는데, 문제가 아주 잘 해결되었습니다.

$("#id1").mouseenter(function(){
                $(this).children().fadeIn(1000);
            }).mouseleave(function(){
                $(this).children().fadeOut(1000);
            });

Mouseenter, mouseleave, mouseover, mouseout 등이 여러 곳에 소개되어 있어서 하나 복사해서 붙여넣었습니다.
/**************************************** *** ************************/
1.mouseover 및 mouseenter
상관없음 마우스 포인터가 선택한 요소를 통과하거나 해당 하위 요소가 마우스 오버 이벤트를 트리거합니다.
mouseenter 이벤트는 마우스 포인터가 선택한 요소를 통과할 때만 트리거됩니다.

2.mouseout 및 mouseleave
mouseout 이벤트는 마우스 포인터가 선택한 요소 또는 하위 요소를 벗어나는지 여부에 따라 트리거됩니다.
mouseleave 이벤트는 마우스 포인터가 선택한 요소를 떠날 때만 트리거됩니다.
/**************************************** ***** *********************/
현상은 이런 현상인데 과정은 약간 모호합니다.
마우스 포인터가 선택한 요소로 이동하면 마우스 포인터가 선택한 요소에서 하위 요소로 이동하면 마우스오버 이벤트가 발생합니다. 선택한 요소의 mouseout 이벤트가 먼저 트리거된 다음 하위 요소의 mouseover 이벤트가 트리거됩니다. 이벤트는 선택한 요소까지 버블링됩니다. 이는 선택한 요소가 먼저 mouseout 이벤트를 실행한 다음 mouseover를 실행하는 것과 같습니다. 이벤트.
확인을 위해 코드를 다음과 같이 변경합니다.

<script type="text/javascript" src=" 
</script><p id="id1" style="width:800px; height:400px; background-color:#F23">
        <p id="id2" style="width:400px; height:300px; background-color:#0F8;  
        position:absolute; top:300px;">
        </p>
    </p><script type="text/javascript">$("#id1").mouseover(function(){
                //$(this).children().fadeIn(1000);
                console.log(&#39;a&#39;);
            }).mouseout(function(){
                //$(this).children().fadeOut(1000);
                console.log(&#39;b&#39;);
            });</script>

페이지에서 id1으로 마우스를 이동한 후 id1에서 id2로 이동하면 콘솔 출력은 아래와 같습니다
JavaScript에서 마우스 오버 및 마우스 아웃의 다중 트리거에 대한 솔루션
id1을 보면 mouseover, mouseout, mouseover 이벤트가 연속적으로 호출되는 것을 볼 수 있는데, 이는 위에서 분석한 것과 똑같습니다.

mouseenter与mouseleave实现分析

原理分析

从上面分析,我们可以看出,要实现mouseenter与mouseleave的效果,就是当鼠标从被选元素移动到其子元素上的时候,被选元素不执行mouseout事件,也不执行子类冒泡过来的mouseover事件,当鼠标从被选元素子元素移动到被选元素上的时候,被选元素不执行mouseover事件,也不执行子类冒泡过来的mouseout事件。
要实现上面的效果,我们需要event对象的一个属性relatedTarget,这个属性就是用来判断 mouseover和mouseout事件目标节点的相关节点的属性。简单的来说就是当触发mouseover事件时,relatedTarget属性代表的就是鼠标刚刚离开的那个节点,当触发mouseout事件时它代表的是鼠标移向的那个对象。由于MSIE不支持这个属性,不过它有代替的属性,分别是 fromElement和toElement。除此,我们还需要contains方法,来判断一个对象是否包含在另外一个对象中。
这样当鼠标移动,需要判断以下两条即可  
1.调用mouseover,只需要判断relatedTarget是否被选元素的子元素,如果是,则不执行(当于从被选元素子元素移动到被选元素,不执行mouseover;当于从被选元素移动到被选元素子元素,不执行冒泡过来的mouseover);  
2.调用mouseout,只需要判断relatedTarget是否被选元素的子元素,如果是,则不执行(当于从被选元素子元素移动到被选元素,不执行子元素冒泡过来的mouseout;当于从被选元素移动到被选元素子元素,不执行mouseover);

实现过程

判断两个元素是否存在包含关系

jquery中封装了contains函数如下  
JavaScript에서 마우스 오버 및 마우스 아웃의 다중 트리거에 대한 솔루션
可以简化为如下

//判断两个a中是否包含b
    function contains(a,b){
            return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);
    }

compareDocumentPosition介绍

这个方法是 DOM Level 3 specification 的一部分,允许你确定 2 个 DOM Node 之间的相互位置。这个方法比 .contains() 强大。这个方法的一个可能应用是排序 DOM Node 成一个详细精确的顺序。NodeA.compareDocumentPosition(NodeB)返回的信息描述如下:

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

通过上面我们就可以理解为什么要写成a.compareDocumentPosition(b) & 16因为如果节点 A 包含节点 B,就会返回16,16&16=1,其他的情况结果都会0。

获取兼容性性的relatedTarget

为了兼容各种浏览器,参考jquery源码,写出如下代码,来获取mouseover和mouseout事件目标节点的相关节点的属性relatedTarget。

function getRelated(e){
        var related;
        var type=e.type.toLowerCase();//这里获取事件名字
        if(type==&#39;mouseover&#39;){
            related=e.relatedTarget||e.fromElement
        }else if(type=&#39;mouseout&#39;){
            related=e.relatedTarget||e.toElement
        }        return related; 
    }

改进mouseover和mouseout

改进mouseover和mouseout以实现改进mouseenter与mouseleave效果,所有代码如下。


    
    

测试,鼠标移动路线如下图路线
JavaScript에서 마우스 오버 및 마우스 아웃의 다중 트리거에 대한 솔루션
由控制台可以很看出,此刻的mouseover和mouseout已经完全具备mouseenter与mouseleave效果效果。
代码的封装
如果每次进行这样的操作,都需要加载Jquery或是写很多代码,将是件繁琐的事,为了便于以后操作,进行了适当的封装,模拟Jquery,生成自己的mouseenter与mouseleave。代码封装到dqMouse.js文件中,如下:

(function(w){
    var dqMouse = function(obj) {
        // 函数体
        return new dqMouse.fn.init(obj);
    }
    dqMouse.fn = dqMouse.prototype = {
        // 扩展原型对象
        obj:null,
        dqMouse: "1.0.0",
        init: function(obj) {
            this.obj=obj;
            return this;
        },
        contains:function(a,b) {
            return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);
        },
        getRelated:function(e) {
            var related;
            var type=e.type.toLowerCase();//这里获取事件名字
            if(type==&#39;mouseover&#39;){
                related=e.relatedTarget||e.fromElement
            }else if(type=&#39;mouseout&#39;){
                related=e.relatedTarget||e.toElement
            }
            return related; 
        },
        over:function(fn){
            var obj=this.obj;
            var _self=this;
            obj.onmouseover=function(e){                
                var related=_self.getRelated(e); 
                if(this!=related && !_self.contains(this,related)){
                    fn();
                }
            }
            return _self;
        },
        out:function(fn){
            var obj=this.obj;
            var _self=this;
            obj.onmouseout=function(e){
                var related=_self.getRelated(e); 
                if(obj!=related && !_self.contains(obj,related)){
                    fn();
                }
            }
            return _self;
        }

    }   
    dqMouse.fn.init.prototype = dqMouse.fn;
    window.dqMouse = window.$$= dqMouse;})(window);

调用的源文件如下:

<p id="id1" style="width:800px; height:400px; background-color:#F23">
        <p id="id2" style="width:400px; height:300px; background-color:#0F8;  position:absolute; top:300px;">
        </p>
    </p>
    <script type="text/javascript" src="dqMouse.js"></script>
    <script type="text/javascript">
    var id1=document.getElementById(&#39;id1&#39;);

    $$(id1).over(function(){
        console.log(&#39;mouseover&#39;);
    }).out(function(){
        console.log(&#39;mouseout&#39;);
    }); 
    </script>

经过测试okey。

 以上就是JavaScript中mouseover和mouseout多次触发解决办法 的内容,更多相关内容请关注PHP中文网(www.php.cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.