首頁  >  文章  >  web前端  >  JavaScript中mouseover和mouseout多次觸發解決方法

JavaScript中mouseover和mouseout多次觸發解決方法

黄舟
黄舟原創
2017-03-01 14:58:381141瀏覽

問題描述

我希望當滑鼠移動到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中mouseover和mouseout多次觸發解決方法

問題解決方案

最開始的問題分析,當滑鼠從id1移動到id2上的時候,由於滑鼠由id2離開進入id1 ,針對id1觸發了一個mouseout事件,於是id2有顯示變為不顯示,接著在滑鼠移動到id2上,在id2上觸發了一個mouseover事件,由於冒泡機制,id2上的mouseover冒泡到id1之前,觸發了id1上的mouseover事件,然後id2由不顯示變為顯示。同理,當滑鼠從id2移動到id1上的時候,針對id2,觸發了一個mouseout事件,還是因為冒泡機制,mouseout事件傳到id1上,id2由顯示變為不顯示,接著滑鼠移動到id1之前,觸發了一個mouseover事件,然後id2有不顯示變成顯示。

看來,上面的問題歸根要解決的是,當滑鼠由id1上移動到id2上的時候,阻止id1的mouseout事件;當滑鼠從id2上移動到id1上的時候,阻止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
不論滑鼠指標穿過被選元素或其子元素,都會觸發mouseover 事件。
只有在滑鼠指標穿過被選元素時,才會觸發 mouseenter 事件。

2.mouseout與mouseleave
不論滑鼠指標離開被選元素或任何子元素,都會觸發 mouseout 事件。
只有在滑鼠指標離開被選元素時,才會觸發 mouseleave 事件。
/************************************* ********************/
現象確實是這個現象,但是過程說的有點模糊,我的理解如下:
當滑鼠指標移動到被選元素,會觸發mouseover 事件,這個大家都知道,當滑鼠指標由被選元素移動到其子元素,先是觸發被選元素的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中mouseover和mouseout多次觸發解決方法
可以看出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中mouseover和mouseout多次觸發解決方法
可以简化为如下

//判断两个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多次觸發解決方法
由控制台可以很看出,此刻的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