• JS子元素oumouseover触发父元素onmouseout


      JavaScript中,父元素包含子元素:
      当父级设置onmouseover及onmouseout时,鼠标从父级移入子级,则触发父级的onmouseout后又触发onmouseover;从子级移入父级后再次触发父级的oumouseout后又触发onmouseover。而如果onmouseover内又应用了计时器便会存在较大的问题。下面针对此问题给出解决方案。
      首先,在给出解决方案之前,必须先弄清楚几个对象及方法,分别如下:
      1、事件对象
      2、事件对象相关属性(只针对onmouseover及onmouseout),即fromElement、toElement、relatedTarget
      3、判断一个元素是否包含另一个元素的方法,即element.contains(Node)与element.compareDocumentPosition(Node)

      既然前面已经说了要弄清如上几个对象及方法,那么,我们就可以分析一下倒底如何去解决这个问题。
    分析:
      存在的问题是设置onmouseover时,鼠标从移入父级内时,没任何问题,但由父级移入子级时,以及由子级称出到父级时会出现如上问题,那么我们可以想办法设置当鼠标从父级移入到子级时,或从子级移出到父级时让触发对象失效,我们可以通过if语句进行判断。而事件对象里面有个属性可以获取移入移出时的相关对象,下面就来介绍。

      1、事件对象:可以获取事件对象的一系列属性,在事件中写一个参数,即可通过参数获取,方法如下:

    1 wrap.onmouseover = function(e) {
    2     e = window.event || e;        // window.event是为了兼容ie下获取事件对象,而e为标准浏览器直接获取
    3 }

      2、事件对象的相关对象
    在触发onmouseover及onmouseout时,必定会涉及到其它对象,如:onmouseover的相关对象,即为哪个对象进入的。onmouseout的相关对象即为进入到哪个对象。获取方法如下:

    1 wrap.onmouseover = function(e) {
    2     e = window.event || e;
    3     var s = e.fromElement || e.relatedTarget;    //e.fromElement为IE下onmouseover获取相关对象方法,relatedTarget为标准浏览器下获取方法
    4 }
    5 wrap.onmouseout = function(e) {
    6     e = window.event || e;
    7     var s = e.toElement || e.relatedTarget;        //e.toElementIE下onmouseout获取相关对象方法,relatedTarget为标准浏览器下获取方法
    8 }

      3、判断一个元素是否包含另一个元素
    IE下可以使用a.contains(b)判断a是否包含b
    标准浏览器下a.compareDocumentPosition(b)有5个值,若为0表示为同一节点,若为2表示a位于b后面,若为4表示a位于b前面,若为10表示a为b的后代,若为20表示a为b的祖级。

      先上个即将用到的示例的HTML及CSS

     1 <!doctype html>
     2 <html>
     3 <head>
     4     <meta charset="UTF-8">
     5     <style type="text/css">
     6     html,body,div{margin:0;padding:0}
     7         .wrapper {
     8             overflow: hidden;
     9             width: 800px;
    10             background: black;
    11         }
    12         .box {
    13             height: 200px;
    14             background: #FF0;
    15             margin: 80px 0;
    16         }
    17     </style>
    18 </head>
    19 <body>
    20     <div class="wrapper" id="wrap">
    21         <div class="box" id="box"></div>
    22     </div>
    23 </body>
    24 </html>

      既然知道了以上的获取属性及事件的必备方法,那么我们就可以想方法解决问题了
    当触发onmouseover时,可能是从对象以外移入的,也有可能是父级移入到子级,以及子级移出到父级,刚才也说过,onmouseover的相关对象是获取从哪个对象进入的。如果是从外面的对象进入的,我们就执行所需的代码。如果是从父级移入到子级或是由子级移出到父级时,则直接跳过。
    父级移入到子级对象,相关对象为父级。 子级移出到父级对象,相对对象为子级。
    代码如下:

     1 wrap.onmouseover = function(e) {
     2     e = window.event || e;
     3     var s = e.fromElement || e.relatedTarget;
     4     if (document.all) {    //判断浏览器是否为IE,如果存在document.all则为IE
     5         if (!this.contains(s)) {    // 判断调用onmouseover的对象(this)是否包含自身或子级,如果包含,则不执行
     6             console.log('IE will over');
     7         }    
     8     } else {    //标准浏览器下的方法
     9         var reg = this.compareDocumentPosition(s);
    10         if (!(reg == 20 || reg == 0)) {
    11             console.log('Browser will over');
    12         }
    13     }
    14 }

      当触发onmouseout时,可能是从父级移到子级,也可能由子级移到父级,或是移出至父级之外。
    父级称到子级,则相关对象为子级,子级称到父级,则相关对象为父级。
    代码如下:

     1 wrap.onmouseout = function(e) {
     2     e = window.event || e;
     3     var s = e.toElement || e.relatedTarget;
     4     if(document.all) {
     5         if (!this.contains(s)) {
     6             console.log('IE will out');
     7         }
     8     } else {
     9         var reg = this.compareDocumentPosition(s);
    10         if (!(reg == 20 || reg == 0)) {
    11             console.log('Browser will out');
    12         }
    13     }
    14 }

    问题也就得到了解决。

    不过你会发现:onmouseover与onmouseout的判断方法其实是一样的。于是我们得到:
    无论是移入还是移出,只要相关对象是父级以外的就可以执行,否则代码不执行。

    最后,再为大家提供本人自己写的兼容代码,复制到JS代码后可直接调用。代码如下:

     1 /* 
     2  * 功能:鼠标移入对象触发事件,兼容所有浏览器并防止鼠标在父子对象间移动造成的触发onmouseover的bug
     3  * 参数:第一个参数表示触发的对象,第二个参数表示触发的对象的事件对象,第三个对象表示要执行的函数
     4  * 作者:http://www.cnblogs.com/wuyuchang/
     5  */
     6 function mouseover(a, e, func) {
     7     e = e || window.event;
     8     var b = e.fromElement || e.relatedTarget;
     9     
    10     mouseoverAndOut(a, b, func);
    11 }
    12 /* 
    13  * 功能:鼠标移出对象触发事件,兼容所有浏览器并防止鼠标在父子对象间移动造成的onmouseout的bug
    14  * 参数:第一个参数表示触发的对象,第二个参数表示触发的对象的事件对象,第三个对象表示要执行的函数
    15  * 作者:http://www.cnblogs.com/wuyuchang/
    16  */
    17 function mouseout(a ,e, func) {
    18     e = e || window.event;
    19     var b = e.toElement || e.relatedTarget;
    20     mouseoverAndOut(a, b, func);
    21 }
    22 /* 
    23  * 功能:鼠标移入或移出对象触发事件,兼容所有浏览器并防止鼠标在父子对象间移动造成的onmouseover & onmouseout的bug
    24  * 参数:第一个参数表示触发的对象,第二个参数表示触发的对象的事件对象,第三个对象表示要执行的函数
    25  * 作者:http://www.cnblogs.com/wuyuchang/
    26  */
    27 function mouseoverOrOut(a, e, func) {
    28     e = e || window.event;
    29     var b;
    30     if (e.type == 'mouseover') {
    31         b = e.fromElement || e.relatedTarget;
    32     } else if (e.type == 'mouseout') {
    33         b = e.toElement || e.relatedTarget;
    34     }
    35     mouseoverAndOut(a, e, func);
    36 }
    37 /* 
    38  * 功能:鼠标移入或移出对象触发事件,兼容所有浏览器并防止鼠标在父子对象间移动造成的onmouseover & onmouseout的bug
    39  * 参数:第一个参数表示触发的对象,第二个参数表示触发的对象的相关对象,第三个对象表示要执行的函数
    40  * 作者:http://www.cnblogs.com/wuyuchang/
    41  */
    42 function mouseoverAndOut(a, b, func) {
    43     if (document.all) {
    44         if (!(a.contains(b))) {
    45             func();
    46         }
    47     } else {
    48         var res = a.compareDocumentPosition(b);
    49         if(!(res == 20 || res == 0)){        
    50                 func();
    51             }       
    52     }           
    53 }

    (如果是onmouseover,调用mouseover(a, e, func)即可;如果是onmouseout,调用mouseout(a, e, func)即可;或不管onmouseover还是onmouseout直接调用mouseoverOrOut(a, e, func)即可。)


    以上为个人经验之谈,如有不到之处还请留言指点。

  • 相关阅读:
    hihocoder 1038
    hihocoder 1039
    poj 2774
    bzoj 4690&&4602
    poj 2417
    STL
    poj 1026
    poj 1064
    poj 1861(prim)
    poj 1129
  • 原文地址:https://www.cnblogs.com/wuyuchang/p/3903608.html
Copyright © 2020-2023  润新知