ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript でのマウスオーバーとマウスアウトの複数のトリガーに対する解決策

JavaScript でのマウスオーバーとマウスアウトの複数のトリガーに対する解決策

黄舟
黄舟オリジナル
2017-03-01 14:58:381141ブラウズ

問題の説明

マウスがid1に移動するとid2が表示され、マウスがid1から離れるとid2が表示されることを望みます。問題は次のとおりです。
1. マウスが id1 から id2 に移動すると、id が表示から非表示に変わり、その後、id2 から id1 に移動すると、id が表示されます。 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 に対してマウスアウト イベントがトリガーされます。または、バブリング メカニズムにより、マウスアウト イベントが id1 に送信され、id2 が表示から非表示に変わり、マウスが移動します。以前は、mouseover イベントがトリガーされ、id2 が非表示から表示に変更されました。

上記の問題の最終的な解決策は、マウスが id1 から id2 に移動するときに id1 のマウスアウト イベントが発生しないようにすること、マウスが id2 から id1 に移動するときに id2 のマウスアウト イベントが発生しないようにすることであるようです。 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 イベントは、マウス ポインターが選択された要素から離れた場合にのみトリガーされます。
/
********************************************* *************/ 現象は確かにこの現象ですが、プロセスは少し曖昧ですが、私の理解は次のとおりです:
マウスポインターが選択された場所に移動したとき。ご存知のとおり、マウス ポインターが選択された要素からその子要素に移動すると、選択された要素の 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が呼び出していることがわかります。マウスオーバー、マウスアウト、マウスオーバー イベントが連続して発生します。これは、上で分析したものとまったく同じです。

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 までご連絡ください。