zoukankan      html  css  js  c++  java
  • onmouseover、onmouseout、onmouseenter、onmouseleave

    1.mouseover与mouseout

    不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout 事件。

    不论鼠标指针穿过被选元素还是任何子元素,都会触发 mouseover 事件。

    解释:当鼠标指针移动到被选元素,会触发 mouseover 事件,这个大家都知道,当鼠标指针由被选元素移动到其子元素,先是触发被选元素的mouseout事件,然后子元素的mouseover事件冒泡到被选元素,此时相当于被选元素先执行了一个mouseout事件,然后执行了一个mouseover事件。

    所以冒泡机制会干扰事件

    2.mouseenter与mouseleave

    只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。
    只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。

    问题描述

    我希望当鼠标移动到id1上的时候,id2显示,当鼠标离开id1的时候,id2显示。问题如下:

    1.当鼠标从id1上移动到id2上的时候,id由有显示变为不显示,然后变为显示

    2.当鼠标从id2上移动到id1上的时候, id2有显示变为不显示,然后变为显示

    我希望的是当鼠标在id1或者id2上移动的时候,id2一直显示,不发生变化。

    问题解决办法

    最开始的问题分析,当鼠标从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代码改为如下,很好解决了问题。

    很多地方都有介绍mouseenter、mouseleave与mouseover、mouseout,于是复制粘贴了一个。

    /*********************************************************/

    1.mouseover与mouseenter

    不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件。

    只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。

    2.mouseout与mouseleave

    不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout 事件。
    只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。

    /*********************************************************/

    现象确实是这个现象,但是过程说的有点模糊,我的理解如下:

    当鼠标指针移动到被选元素,会触发 mouseover 事件,这个大家都知道,当鼠标指针由被选元素移动到其子元素,先是触发被选元素的mouseout事件,然后子元素的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函数如下

    这里写图片描述 

    可以简化为如下

    1
    2
    3
    4
    //判断两个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)返回的信息描述如下:

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

    获取兼容性性的relatedTarget

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function getRelated(e){
    var related;
    var type=e.type.toLowerCase();//这里获取事件名字
    if(type=='mouseover'){
    related=e.relatedTarget||e.fromElement
    }else if(type='mouseout'){
    related=e.relatedTarget||e.toElement
    }
    return related;
    }

    改进mouseover和mouseout

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

    //判断两个a中是否包含b
    function contains(a,b){
    return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);
    }
     
    function getRelated(e){
    var related;
    var type=e.type.toLowerCase();//这里获取事件名字
    if(type=='mouseover'){
    related=e.relatedTarget||e.fromElement
    }
    else if(type='mouseout'){
    related=e.relatedTarget||e.toElement
    }
    return related;
    }
     
    $(function(){
    $("#id1").mouseover(function(e){
    //判断鼠标从哪移到id1上面
    var related=getRelated(e);
    //如果related是id1的子元素id2,即从子元素id2移动到id1,或是related为id1,即从id1移动到其子元素id2上面,则不进行任何操作,否则进行相应的操作
    if(this!=related && !contains(this,related)){
    console.log('mouseover');
    }
    }).mouseout(function(e){
    //判断鼠标要从id1上面移动到哪去?
    var related=getRelated(e);
    //如果related是id1,即当id1从其子元素移动到id1上,或是related是id2,即从id1上移动到其子元素,不进行任何操作,否则进行相应的操作
    if(this !=related && !contains(this,related)){
    console.log('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 == 'mouseover'){
    related=e.relatedTarget||e.fromElement
    }
    else if(type ='mouseout'){
    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);

    调用的源文件如下:

     
    var id1=document.getElementById('id1');
    $$(id1).over(function(){
    console.log('mouseover');
    }).out(function(){
    console.log('mouseout');
    });
    来源:https://www.jb51.net/article/85977.htm
  • 相关阅读:
    BNU 33693——Problemsetting——————【枚举+最大流】
    HDU 5656 ——CA Loves GCD——————【dp】
    HZAU 21——Arithmetic Sequence——————【暴力 or dp】
    HZAU 18——Array C——————【贪心】
    BNU 20950 ——沉重的货物 —————— · 最短路、最短边最大化」
    vim创建新的命令
    vim 配置文件——部分配置
    nyoj 1239——引水工程——————【最小生成树 prim】
    内部排序 ——第3波——————【快速排序】
    PostgreSQL 安装配置 (亲测可用)
  • 原文地址:https://www.cnblogs.com/icctuan/p/12105845.html
Copyright © 2011-2022 走看看