关于onmouseenter和onmouselever

一般事件 事件 浏览器支持 描述
onClick IE3|N2|O3 鼠标点击事件,多用在某个对象控制的范围内的鼠标点击
onDblClick IE4|N4|O 鼠标双击事件
onMouseDown IE4|N4|O 鼠标上的按钮被按下了
onMouseUp IE4|N4|O 鼠标按下后,松开时激发的事件
onMouseOver IE3|N2|O3 当鼠标移动到某对象范围的上方时触发的事件 有冒泡事件

onMouseOut IE4|N3|O3 当鼠标离开某对象范围时触发的事件
onMouseEnter当鼠标移动到某对象范围的上方时触发的事件 没有冒泡事件

onMouseleave  当鼠标离开某对象时触发的事件
onMouseMove IE4|N4|O 鼠标移动时触发的事件
onKeyPress IE4|N4|O 当键盘上的某个键被按下并且释放时触发的事件.[注意:页面内必须有被聚焦的对象]
onKeyDown IE4|N4|O 当键盘上某个按键被按下时触发的事件[注意:页面内必须有被聚焦的对象]
onKeyUp IE4|N4|O 当键盘上某个按键被按放开时触发的事件[注意:页面内必须有被聚焦的对象]
页面相关事件 事件 浏览器支持 描述
onAbort IE4|N3|O 图片在下载时被用户中断
onBeforeUnload IE4|N|O 当前页面的内容将要被改变时触发的事件
onError IE4|N3|O 捕抓当前页面因为某种原因而出现的错误,如脚本错误与外部数据引用的错误
onLoad IE3|N2|O3 页面内空完成传送到浏览器时触发的事件,包括外部文件引入完成
onMove IE|N4|O 浏览器的窗口被移动时触发的事件
onResize IE4|N4|O 当浏览器的窗口大小被改变时触发的事件
onScroll IE4|N|O 浏览器的滚动条位置发生变化时触发的事件
onStop IE5|N|O 浏览器的停止按钮被按下时触发的事件或者正在下载的文件被中断
onUnload IE3|N2|O3 当前页面将被改变时触发的事件
表单相关事件 事件 浏览器支持 描述
onBlur IE3|N2|O3 当前元素失去焦点时触发的事件 [鼠标与键盘的触发均可]
onChange IE3|N2|O3 当前元素失去焦点并且元素的内容发生改变而触发的事件 [鼠标与键盘的触发均可]
onFocus IE3|N2|O3 当某个元素获得焦点时触发的事件
onReset IE4|N3|O3 当表单中RESET的属性被激发时触发的事件
onSubmit IE3|N2|O3 一个表单被递交时触发的事件
滚动字幕事件 事件 浏览器支持 描述
onBounce IE4|N|O 在Marquee内的内容移动至Marquee显示范围之外时触发的事件
onFinish IE4|N|O 当Marquee元素完成需要显示的内容后触发的事件
onStart IE4|N|O 当Marquee元素开始显示内容时触发的事件
编辑事件 事件 浏览器支持 描述
onBeforeCopy IE5|N|O 当页面当前的被选择内容将要复制到浏览者系统的剪贴板前触发的事件
onBeforeCut IE5|N|O 当页面中的一部分或者全部的内容将被移离当前页面[剪贴]并移动到浏览者的系统剪贴板时触发的事件
onBeforeEditFocus IE5|N|O 当前元素将要进入编辑状态
onBeforePaste IE5|N|O 内容将要从浏览者的系统剪贴板传送[粘贴]到页面中时触发的事件
onBeforeUpdate IE5|N|O 当浏览者粘贴系统剪贴板中的内容时通知目标对象
onContextMenu IE5|N|O 当浏览者按下鼠标右键出现菜单时或者通过键盘的按键触发页面菜单时触发的事件 [试试在页面中的<body>中加入onContentMenu="return false"就可禁止使用鼠标右键了]
onCopy IE5|N|O 当页面当前的被选择内容被复制后触发的事件
onCut IE5|N|O 当页面当前的被选择内容被剪切时触发的事件
onDrag IE5|N|O 当某个对象被拖动时触发的事件 [活动事件]
onDragDrop IE|N4|O 一个外部对象被鼠标拖进当前窗口或者帧
onDragEnd IE5|N|O 当鼠标拖动结束时触发的事件,即鼠标的按钮被释放了
onDragEnter IE5|N|O 当对象被鼠标拖动的对象进入其容器范围内时触发的事件
onDragLeave IE5|N|O 当对象被鼠标拖动的对象离开其容器范围内时触发的事件
onDragOver IE5|N|O 当某被拖动的对象在另一对象容器范围内拖动时触发的事件
onDragStart IE4|N|O 当某对象将被拖动时触发的事件
onDrop IE5|N|O 在一个拖动过程中,释放鼠标键时触发的事件
onLoseCapture IE5|N|O 当元素失去鼠标移动所形成的选择焦点时触发的事件
onPaste IE5|N|O 当内容被粘贴时触发的事件
onSelect IE4|N|O 当文本内容被选择时的事件
onSelectStart IE4|N|O 当文本内容选择将开始发生时触发的事件
数据绑定 事件 浏览器支持 描述
onAfterUpdate IE4|N|O 当数据完成由数据源到对象的传送时触发的事件
onCellChange IE5|N|O 当数据来源发生变化时
onDataAvailable IE4|N|O 当数据接收完成时触发事件
onDatasetChanged IE4|N|O 数据在数据源发生变化时触发的事件
onDatasetComplete IE4|N|O 当来子数据源的全部有效数据读取完毕时触发的事件
onErrorUpdate IE4|N|O 当使用onBeforeUpdate事件触发取消了数据传送时,代替onAfterUpdate事件
onRowEnter IE5|N|O 当前数据源的数据发生变化并且有新的有效数据时触发的事件
onRowExit IE5|N|O 当前数据源的数据将要发生变化时触发的事件
onRowsDelete IE5|N|O 当前数据记录将被删除时触发的事件
onRowsInserted IE5|N|O 当前数据源将要插入新数据记录时触发的事件
数据绑定 事件 浏览器支持 描述
onAfterPrint IE5|N|O 当文档被打印后触发的事件
onBeforePrint IE5|N|O 当文档即将打印时触发的事件
onFilterChange IE4|N|O 当某个对象的滤镜效果发生变化时触发的事件
onHelp IE4|N|O 当浏览者按下F1或者浏览器的帮助选择时触发的事件
onPropertyChange IE5|N|O 当对象的属性之一发生变化时触发的事件
onReadyStateChange IE4|N|O 当对象的初始化属性值发生变化时触发的事件











昨天去 大牛 司徒正美 的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);
        };
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值