`
myten
  • 浏览: 134027 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于 onmouseenter 和onmouseleave

 
阅读更多
昨天去 大牛 司徒正美 的blog 看博文  突然看到 关于 onmouseenter 和onmouseleave 两个ie专有事件..
写了这么久 js应用 我居然不知道这两个事件 于是 去google搜索了一番. 才发现这两个事件 是如此的优秀 且好用... 但搜索过程中 发现 好多人 似乎不太明白这两个事件 和mouseover mouseout 真正的区别 和用途..  并且看到google中搜索得到的 一些朋友 实现的 跨浏览器 解决方案. 觉得似乎有些繁琐...所以产生了写一篇blog 把这玩意 说透彻的冲动... 好啦.我们进入正题.

对于 mouseover 和mouseenter 两个事件 最大的区别就是 mouseenter 是 不冒泡的事件 ..这话怎么理解呢?
<div id=="parent">
<div id="child"></div>
</div>

对于mouseover 时间来说 当鼠标从其他元素 移动到 child节点时发生 但此事件会冒泡 所以会导致 parent 也出发mouseover
如果我们对 parent注册了 mouseover监听. 则可能会产生一个什么问题呢? 从 parent移动到child 同样出发parent的mouseover  有时候我们不希望这样的事情发生. 这时候 如果注册的监听 是mouseenter的话  无论鼠标从任何元素 移动到child时 只有child元素 发生mouseenter事件 而其祖宗节点 都不会因为冒泡 而触发此事件...这就 使我们可以彻底放弃  我们以往为了 实现同样的逻辑  又要对子节点禁止mouseover冒泡 或者又去判断事件源对象 或判断srcElement/relatedTarget 那样麻烦的方案.
对于 mouseout 和mouseleave 也是如此 当鼠标从child 移出时 mouseout同样会冒泡到 parent 从而触发parent的 mouseout 二mouseleave 同样无此问题.

知道了区别 剩下的事情就好办多了. 遇到此类需求 我们一律mouseenter mouseleave就好..问题是 这玩意只有ie支持 怎么办呢?
我们只能 用mouseover 和mouseout来模拟  但是如果我们的模拟方案 太过复杂 那是在就意义不大了... 这时候我们就可以 借助 xml 方法compareDocumentPosition 来彻底解决这个问题
我在我的类库中 封装了一个方法 专门用来判断 某个节点的位置 是否在另一个节点的子节点中...
ie可以用 parentNode.contains(childNode) 来判断 这没什么好说的 childNode在parentNode DOM树中存在 那么就是true
而contains方法 ie专属 那么 我们就是借助 !!(node.compareDocumentPosition(node2) &16) 来实现同样的效果.
那么接下来 我们就来谈谈 compareDocumentPosition 方法 否则 你看到上面的 &16 一定会困惑无比...

compareDocumentPosition 方法在非ie浏览器 都被实现到 节点对象的 中了  所以
node.compareDocumentPosition(node2) 的作用就是 比较 node节点与node2节点之间的位置关系..
他的返回值是一个number值...
一般来说 对我们有用的 是以下几个值
1.  20  (2进制: 010100)
2.  10  (2进制:   001010)
3.  4    (2进制:   000100)
4.  2    (2进制:   000010)
5.  0    (2进制:   000000)
6.  2进100***的数...
那么这些 20 10 4 2 0 是怎么来的呢? 我们接着往下 看...

试试上 这个2进制算法 是专门用来解释 两个节点之间的关系的

这个 6位2进制数 才是根本所在
第6位 代表 两个节点是否一个在DOM树上一个不在 这个是针对整个DOM树而言的.也就是说 如果两个都不在 或两个都在 则为0 否则为1
第5位 代表node是否是node2的父节点 如果是 则为1 否则为0
第4位 代表node是否是node2的子节点 如果是则为1 否则为0
第3位 代表node是否在node2的前面 如果是 则为1 否则为0 (注:如果node是node2的父节则node同时也看做在node2的前面)
第2位 代表node是否在node2的后面 如果是 则为1 否则为0 (注如果node是node2的子节点 则node同时也看做在node2的后面)
最后 如果 2 3 4 5 6 位 都为0 即 000000 说明 两个节点 要么同时在DOM树上 要么同时不在. 且 两个节点 没有任何关系 那么只有一种可能 即两个节点是同一个节点...也就是 node==node2

所以 node.compareDocumentPosition(node2) &16 位运算 的结果是什么呢? 以上几种可能的组合中只有 010100 &010000 以及 110*** &16 的结果是 010000 即返回16 其他情况  均返回 0 然后 用!! 吧number隐式转型成boolean类型 我们就可以判断出 node是否是 node2的父节点了...
所以 我们也可以使用 node2.compareDocumentPosition(node) & 8 来判断node2 是不是 node的子节点 道理是同样的
或者我们也可以直接 node.compareDocumentPosition(node2) ==20 来做判断 这样还可以省略 !! 做转型..也是可以的.

到了这里 聪明你的 一定发现 这玩意是什么? 分明就是c#中  flag 标识枚举 的用法...
c# 中 File.Attributes 枚举 可能同时具备 n多属性 比如一个文件 可以是 只读的同时 还可以是 隐藏的 或者同时还可以是 共享的. 等等
那么 用一个枚举 值 如何确定 一个文件同时具备哪些属性 又不产生冲突呢? 答案 于 compareDocumentPosition是一样的...

我用js 实现了一个 类似逻辑 来管理 flag标识的类 来说明这个问题 代码如下
// flag 类
    function flag(sFlags) {
        this._flags = {};
        this._status = 0;
        sFlags && this.initFlags(sFlags);
    }
    flag.prototype = {
        constructor: flag,
        initFlags: function(sFlags) {//sFlags "状态1,状态2,状态3...... 初始化原始标识集合...
            sFlags = sFlags.split(',');
            for (var i = 0, len = sFlags.length; i < len; i++) this._flags[sFlags[i]] = 1 << i;
           //这里初始化标识的值 如果同时具备n种状态 则 每种状态的值一定是 000001  000010 000100 001000 010000 100000
        },
        setStatus: function(sFlags) { //sFlags "状态1,状态3......设置当前状态
            sFlags = sFlags.split(',');
    this._status=0;
            for (var i = 0, len = sFlags.length; i < len; i++) {
                this._check[sFlags[i]];
                this._status |= this._flags[sFlags[i]];
            }
        },
        addStatus: function(sFlags) {//sFlags "状态1,状态3......检查当前状态标示 是否有 状态1和状态3 如果没有则添加
            sFlags = sFlags.split(',');
            for (var i = 0, len = sFlags.length; i < len; i++) {
                this._check(sFlags[i]);
                if (this.hasStatus(sFlags[i])) continue; //判断是否已经有这个状态如果有 跳过.
                this._status |= this._flags[sFlags[i]];
                //当前的状态值 与 允许的标识值 做 | 运算 即添加状态
            }
        },
        removeStatus: function(sFlags) {
            sFlags = sFlags.split(',');
            for (var i = 0, len = sFlags.length; i < len; i++) {
                this._check(sFlags[i]);
                if (!this.hasStatus(sFlags[i])) continue;
                this._status ^= this._flags[sFlags[i]];
                // 当前状态值 与 要去掉的状态值做 ^运算 即删除状态
            }
        },
        clear: function() {
            this._status = 0;
        },
        hasStatus: function(sFlags) {//sFlags "状态1,状态3.....状态 n.检查当前状态标识 是否同时 具备状态1和状态3 以及状态n
            sFlags = sFlags.split(',');
            for (var i = 0, len = sFlags.length; i < len; i++) {
                this._check(sFlags[i]);
                if ((this._status & this._flags[sFlags[i]]) != this._flags[sFlags[i]]) return false;
                //当前状态值 与输入的状态做 & 运算  如果返回值 不等于 改状态 的标识值 则 return false .
               //比如 010101 & 010000 返回010000则 说明当前标识值具备 010000这个状态.
            }
            return true;
        },
        _check: function(sFlag) {
            if (!sFlag in this._flags) throw new Error(" 当前 flag 中不存在" + sFlag + "标识");
            //检查当前输入状态字符串 是否是合法值.
        }
    }

用法:
var fileStatus=new flag('readOnly,hidden,otherStatus');
fileStatus.setStatus('readOnly,hidden');
alert(fileStatus.hasStatus('readOnly'))//true;
alert(fileStatus.hasStatus('hidden'))//true;
alert(fileStatus.hasStatus('otherStatus'))//false;


最后 我们回到正题 我们借助 compareDocumentPosition 来模拟 mouseenter mouseleave

DOM结构:
01
<div id="dd" style="background-color:#369;width:50%;height:50%;position:absolute;left:25%;top:25%;" >
02
    <div style="background-color:#ff0;width:50%;height:50%;position:relative;left:25%;top:25%" >
03
        <div style="background-color:#789;width:50%;height:50%;position:relative;left:25%;top:25%" >
04
            <div style="background-color:#123;width:50%;height:50%;position:relative;left:25%;top:25%" >
05
                <div style="background-color:#456;width:50%;height:50%;position:relative;left:25%;top:25%" >
06
                </div>
07
            </div>
08
        </div>
09
    </div>
10
</div>

js脚本:
 

    var dd = document.getElementById('dd')
    if (! +'\v1') {//ie
        dd.onmouseenter = function() { alert(1); };
        dd.onmouseleave = function() { alert(2); };
    }
    else {//others
        dd.onmouseover = function(e) {
            var t = e.relatedTarget;
            var t2 = e.target;
            this == t2 && t && !(t.compareDocumentPosition(this) & && alert(1);
        };
        dd.onmouseout = function(e) {
            var t = e.relatedTarget;
            var t2 = e.target;
            this == t2 && t && !(t.compareDocumentPosition(this) & && alert(2);
        };
    }
原文地址:http://www.cnblogs.com/_franky/archive/2010/05/01/1725624.html
分享到:
评论
5 楼 kingterrors 2014-06-24  
  
4 楼 丛林之王 2013-05-02  
现在火狐也支持...
3 楼 softor 2013-02-19  
楼主,2楼的观点你怎么看?
2 楼 pml346680914 2013-01-08  
太复杂了,绑定事件时指定不向上冒泡不就行了。
1 楼 pdsmsf 2011-10-26  
顶一个

相关推荐

    javascript 兼容FF的onmouseenter和onmouseleave的代码

    ### 标题知识点:javascript 兼容FF的onmouseenter和onmouseleave的代码 在网页开发中,事件处理是一项基础而重要的技术。在不同的浏览器中,对于同一种事件的处理可能会存在差异。例如,Internet Explorer(IE)...

    D7自定义Panel,添加鼠标进出事件

    在Delphi 7中,Panel控件作为常用的布局容器,提供了丰富的功能,但默认情况下并未直接提供鼠标进入(OnMouseEnter)和鼠标离开(OnMouseLeave)事件。这两个事件在许多用户界面设计中非常有用,例如高亮显示、提示...

    javascript中onmouse事件在div中失效问题的解决方法

    在IE下解决问题很简单,用onMouseEnter、onMouseLeave来代替onMouseOver、onMouseOut就行了,他们的作用基本相同,但前者不会发生冒泡(如果用 jQuery的event事件,只要绑定mouseleave、mouseenter即可)。...

    Alpha Controls 12.18

    Improved repaint of some controls ...Added OnMouseEnter and OnMouseLeave events in the TsGauge component Added the "sclLeftLeft" parameter in the BoundLabel.Layout property A lot of small improvements

    Delphi 菜单的Hint (Delphi 2007)

    4. **处理OnMouseEnter和OnMouseLeave事件**:为了实现类似ShowHint的效果,可以为TMenuItem添加OnMouseEnter和OnMouseLeave事件处理程序。当鼠标进入菜单项时,显示Hint;离开时,隐藏Hint。这可以通过控制...

    G:\Temp\KSDev.TrayClock.v1.04.rar

    + Handle all standard events - OnClick, OnMouseDown, OnMouseUp, OnMouseMove, OnMouseEnter, OnMouseLeave + Support standard hint + Handle custom hint window + Supports Windows95/98/Me/NT/2000/XP/2003

    C#自定义控件-获焦点后自动放大按钮

    4. **在适当的地方调用Enlarge和Restore方法**:在`OnMouseEnter`和`OnMouseLeave`中调用相应的放大和恢复方法。 ```csharp protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); Enlarge...

    BalloonHint

    这是一个在Delphi2010中提供的气泡形提示用的组件,在Delphi2007中是没有的。本人从Delphi2010中将它抠出来... 这里提供一个例子说明它的用法:仅需编写需要显示提示信息的组件的OnMouseEnter、OnMouseLeave事件即可。

    AlphaControls_12.18_Stable

    * Added OnMouseEnter and OnMouseLeave events in the TsGauge component * Added the "sclLeftLeft" parameter in the BoundLabel.Layout property * A lot of small improvements * Added new "Flat Box" ...

    react-native-macos:https的分叉

    支持onMouseEnter和onMouseLeave事件( ) 重新实现本地hitSlop道具( ) 创建一个库来播放声音( ) 支持pointerEvents道具( ) 添加组件( ) 添加组件( ) 将cursor道具添加到&lt;View&gt; ( ) 派生@react-...

    快速移动鼠标触发问题及解决方法(ECharts外部调用保存为图片操作及工作流接线mouseenter和mouseleave)

    记录两个项目开发中遇到的问题,一个是ECharts外部调用保存为图片操作,一个是workflow工作流连接曲线onmouseenter和onmouseleave事件由于鼠标移动过快触发问题。 一、外部按钮调用ECharts图表的保存为图片操作 ...

    SkinDemo_fireplacel1g_Vc_

    在本项目中,开发者可能自定义了一个CButton派生类,重载了OnMouseEnter和OnMouseLeave等消息处理函数,以实现当鼠标进入和离开按钮时改变颜色的效果。颜色变化可以通过设置控件的背景色或者使用位图刷来实现。 ...

    阿龙自定义Button和Textbox

    这可以通过重写OnMouseEnter和OnMouseLeave方法实现: ```csharp public class CustomButton : Button { protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); this.BackColor = Color....

    C#自定义控件--美化ComboBox源码

    3. 鼠标悬停效果:在OnMouseEnter和OnMouseLeave事件中改变控件的外观,如边框颜色、背景色等,以增加交互感。 4. 下拉箭头:可以自定义下拉箭头的形状和颜色,甚至可以将其替换为其他图标。 二、扩展功能 1. 搜索...

    自编的按钮控件

    例如,可以增加一个新的自定义属性来存储按钮在鼠标悬停时的颜色,同时在OnMouseEnter和OnMouseLeave事件中分别改变字体颜色。此外,为了实现漂亮的图片按钮效果,可能需要利用TImage组件加载图片,并在按钮的...

    C#自定义控件案例--美化GroupBox2019

    - **鼠标交互**:添加鼠标事件处理程序,如OnMouseEnter和OnMouseLeave,改变鼠标悬停时的外观效果,增加反馈感。 4. **代码实现**: 在C#代码中,我们需要创建一个新的类,比如MyGroupBox,继承自GroupBox,并...

    delphi自定义的label_hint单元

    4. 要实现这个功能,我们需要覆盖TLabel的OnMouseEnter和OnMouseLeave事件。在OnMouseEnter中显示Hint,在OnMouseLeave中隐藏Hint。如下所示: ```delphi procedure TCustomLabel.ShowHint(Sender: TObject); begin ...

    渐变式弹出式消息框,实现了窗体渐变,窗体停靠,鼠标经过自动弹出

    例如,可以使用TTimer组件来控制消息框的显示和隐藏时间,用OnMouseEnter和OnMouseLeave事件处理鼠标进入和离开的消息,再配合TAlphaColor和AnimateSmooth方法来实现渐变效果。 总之,这个项目展示了如何通过巧妙的...

    20090924 透明的CHECKBOX 和RADIOBUTTON.rar

    另外,为了实现动态的透明效果,如鼠标悬停或被选中的状态变化,开发者可能还会处理OnMouseEnter、OnMouseLeave、OnClick等事件,根据不同的状态改变控件的外观。 此外,Delphi的皮肤化库,如TMS Software的...

    C# 自定义控件 自定义Button控件 水晶按钮

    为了增加交互性,我们还可以重写鼠标事件处理程序,比如OnMouseEnter和OnMouseLeave,以改变按钮在鼠标悬停时的外观: ```csharp protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); //...

Global site tag (gtag.js) - Google Analytics