最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

跨瀏覽器的 mouseenter mouseleave 以及 compareDocumentPosition的使用說明

 更新時間:2010年05月04日 16:49:49   作者:  
昨天去 大牛 司徒正美 的blog 看博文 突然看到 關(guān)于 onmouseenter 和onmouseleave 兩個ie專有事件..

寫了這么久 js應(yīng)用 我居然不知道這兩個事件 于是 去google搜索了一番. 才發(fā)現(xiàn)這兩個事件 是如此的優(yōu)秀 且好用... 但搜索過程中 發(fā)現(xiàn) 好多人 似乎不太明白這兩個事件 和mouseover mouseout 真正的區(qū)別 和用途..  并且看到google中搜索得到的 一些朋友 實現(xiàn)的 跨瀏覽器 解決方案. 覺得似乎有些繁瑣...所以產(chǎn)生了寫一篇blog 把這玩意 說透徹的沖動... 好啦.我們進(jìn)入正題.

對于 mouseover 和mouseenter 兩個事件 最大的區(qū)別就是 mouseenter 是 不冒泡的事件 ..這話怎么理解呢?

<div id=="parent">
<div id="child"></div>
</div>

對于mouseover 時間來說 當(dāng)鼠標(biāo)從其他元素 移動到 child節(jié)點時發(fā)生 但此事件會冒泡 所以會導(dǎo)致 parent 也出發(fā)mouseover

如果我們對 parent注冊了 mouseover監(jiān)聽. 則可能會產(chǎn)生一個什么問題呢? 從 parent移動到child 同樣出發(fā)parent的mouseover  有時候我們不希望這樣的事情發(fā)生. 這時候 如果注冊的監(jiān)聽 是mouseenter的話  無論鼠標(biāo)從任何元素 移動到child時 只有child元素 發(fā)生mouseenter事件 而其祖宗節(jié)點 都不會因為冒泡 而觸發(fā)此事件...這就 使我們可以徹底放棄  我們以往為了 實現(xiàn)同樣的邏輯  又要對子節(jié)點禁止mouseover冒泡 或者又去判斷事件源對象 或判斷srcElement/relatedTarget 那樣麻煩的方案.

對于 mouseout 和mouseleave 也是如此 當(dāng)鼠標(biāo)從child 移出時 mouseout同樣會冒泡到 parent 從而觸發(fā)parent的 mouseout 二mouseleave 同樣無此問題.

 

知道了區(qū)別 剩下的事情就好辦多了. 遇到此類需求 我們一律mouseenter mouseleave就好..問題是 這玩意只有ie支持 怎么辦呢?

我們只能 用mouseover 和mouseout來模擬  但是如果我們的模擬方案 太過復(fù)雜 那是在就意義不大了... 這時候我們就可以 借助 xml 方法compareDocumentPosition 來徹底解決這個問題

我在我的類庫中 封裝了一個方法 專門用來判斷 某個節(jié)點的位置 是否在另一個節(jié)點的子節(jié)點中...

ie可以用 parentNode.contains(childNode) 來判斷 這沒什么好說的 childNode在parentNode DOM樹中存在 那么就是true 

而contains方法 ie專屬 那么 我們就是借助 !!(node.compareDocumentPosition(node2) &16) 來實現(xiàn)同樣的效果.

那么接下來 我們就來談?wù)?compareDocumentPosition 方法 否則 你看到上面的 &16 一定會困惑無比...

 

compareDocumentPosition 方法在非ie瀏覽器 都被實現(xiàn)到 節(jié)點對象的 中了  所以

node.compareDocumentPosition(node2) 的作用就是 比較 node節(jié)點與node2節(jié)點之間的位置關(guān)系..

他的返回值是一個number值...

一般來說 對我們有用的 是以下幾個值

1.  20  (2進(jìn)制: 010100)

2.  10  (2進(jìn)制:   001010)

3.  4    (2進(jìn)制:   000100)

4.  2    (2進(jìn)制:   000010) 

5.  0    (2進(jìn)制:   000000)

6.  2進(jìn)100***的數(shù)...

那么這些 20 10 4 2 0 是怎么來的呢? 我們接著往下 看...

 

試試上 這個2進(jìn)制算法 是專門用來解釋 兩個節(jié)點之間的關(guān)系的

 

這個 6位2進(jìn)制數(shù) 才是根本所在

第6位 代表 兩個節(jié)點是否一個在DOM樹上一個不在 這個是針對整個DOM樹而言的.也就是說 如果兩個都不在 或兩個都在 則為0 否則為1

第5位 代表node是否是node2的父節(jié)點 如果是 則為1 否則為0

第4位 代表node是否是node2的子節(jié)點 如果是則為1 否則為0

第3位 代表node是否在node2的前面 如果是 則為1 否則為0 (注:如果node是node2的父節(jié)則node同時也看做在node2的前面)

第2位 代表node是否在node2的后面 如果是 則為1 否則為0 (注如果node是node2的子節(jié)點 則node同時也看做在node2的后面)

最后 如果 2 3 4 5 6 位 都為0 即 000000 說明 兩個節(jié)點 要么同時在DOM樹上 要么同時不在. 且 兩個節(jié)點 沒有任何關(guān)系 那么只有一種可能 即兩個節(jié)點是同一個節(jié)點...也就是 node==node2

 

所以 node.compareDocumentPosition(node2) &16 位運算 的結(jié)果是什么呢? 以上幾種可能的組合中只有 010100 &010000 以及 110*** &16 的結(jié)果是 010000 即返回16 其他情況  均返回 0 然后 用!! 吧number隱式轉(zhuǎn)型成boolean類型 我們就可以判斷出 node是否是 node2的父節(jié)點了...

所以 我們也可以使用 node2.compareDocumentPosition(node) && 8 來判斷node2 是不是 node的子節(jié)點 道理是同樣的

或者我們也可以直接 node.compareDocumentPosition(node2) ==20 來做判斷 這樣還可以省略 !! 做轉(zhuǎn)型..也是可以的.

 

到了這里 聰明你的 一定發(fā)現(xiàn) 這玩意是什么? 分明就是c#中  flag 標(biāo)識枚舉 的用法...

c# 中 File.Attributes 枚舉 可能同時具備 n多屬性 比如一個文件 可以是 只讀的同時 還可以是 隱藏的 或者同時還可以是 共享的. 等等

那么 用一個枚舉 值 如何確定 一個文件同時具備哪些屬性 又不產(chǎn)生沖突呢? 答案 于 compareDocumentPosition是一樣的...

 

我用js 實現(xiàn)了一個 類似邏輯 來管理 flag標(biāo)識的類 來說明這個問題 代碼如下

// flag 類
    function flag(sFlags) {
        this._flags = {};
        this._status = 0;
        sFlags && this.initFlags(sFlags);
    }
    flag.prototype = {
        constructor: flag,
        initFlags: function(sFlags) {//sFlags "狀態(tài)1,狀態(tài)2,狀態(tài)3...... 初始化原始標(biāo)識集合...
            sFlags = sFlags.split(',');
            for (var i = 0, len = sFlags.length; i < len; i++) this._flags[sFlags[i]] = 1 << i;

           //這里初始化標(biāo)識的值 如果同時具備n種狀態(tài) 則 每種狀態(tài)的值一定是 000001  000010 000100 001000 010000 100000 
        },
        setStatus: function(sFlags) { //sFlags "狀態(tài)1,狀態(tài)3......設(shè)置當(dāng)前狀態(tài)
            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 "狀態(tài)1,狀態(tài)3......檢查當(dāng)前狀態(tài)標(biāo)示 是否有 狀態(tài)1和狀態(tài)3 如果沒有則添加
            sFlags = sFlags.split(',');
            for (var i = 0, len = sFlags.length; i < len; i++) {
                this._check(sFlags[i]);
                if (this.hasStatus(sFlags[i])) continue; //判斷是否已經(jīng)有這個狀態(tài)如果有 跳過.
                this._status |= this._flags[sFlags[i]];

                //當(dāng)前的狀態(tài)值 與 允許的標(biāo)識值 做 | 運算 即添加狀態(tà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]];

                // 當(dāng)前狀態(tài)值 與 要去掉的狀態(tài)值做 ^運算 即刪除狀態(tài)
            }
        },
        clear: function() {
            this._status = 0;
        },
        hasStatus: function(sFlags) {//sFlags "狀態(tài)1,狀態(tài)3.....狀態(tài) n.檢查當(dāng)前狀態(tài)標(biāo)識 是否同時 具備狀態(tài)1和狀態(tài)3 以及狀態(tài)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;

                //當(dāng)前狀態(tài)值 與輸入的狀態(tài)做 & 運算  如果返回值 不等于 改狀態(tài) 的標(biāo)識值 則 return false .

               //比如 010101 & 010000 返回010000則 說明當(dāng)前標(biāo)識值具備 010000這個狀態(tài).

            }
            return true;
        },
        _check: function(sFlag) {
            if (!sFlag in this._flags) throw new Error(" 當(dāng)前 flag 中不存在" + sFlag + "標(biāo)識");

            //檢查當(dāng)前輸入狀態(tài)字符串 是否是合法值.
        }
    }

 

 用法:

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結(jié)構(gòu):

<div id="dd" style="background-color:#369;width:50%;height:50%;position:absolute;left:25%;top:25%;" >
    <div style="background-color:#ff0;width:50%;height:50%;position:relative;left:25%;top:25%" >
        <div style="background-color:#789;width:50%;height:50%;position:relative;left:25%;top:25%" >
            <div style="background-color:#123;width:50%;height:50%;position:relative;left:25%;top:25%" >
                <div style="background-color:#456;width:50%;height:50%;position:relative;left:25%;top:25%" >
                </div>
            </div>
        </div>
    </div>
</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) & 8) && alert(1);
        };
        dd.onmouseout = function(e) {
            var t = e.relatedTarget;
            var t2 = e.target;
            this == t2 && t && !(t.compareDocumentPosition(this) & 8) && alert(2);
        };
    }

大功告成!!!!!

相關(guān)文章

  • JavaScript中new操作符使用詳解

    JavaScript中new操作符使用詳解

    new操作符是JavaScript中創(chuàng)建對象實例的重要方式,理解new操作符的工作原理對于掌握J(rèn)avaScript的面向?qū)ο缶幊讨陵P(guān)重要,本文將詳細(xì)介紹new操作符的原理及實現(xiàn),感興趣的小伙伴跟著小編一起來看看吧
    2024-11-11
  • 詳解如何提升JSON.stringify()的性能

    詳解如何提升JSON.stringify()的性能

    這篇文章主要介紹了詳解如何提升JSON.stringify()的性能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • javascript簡寫效果“神秘的眼睛”

    javascript簡寫效果“神秘的眼睛”

    “眼睛跟隨鼠標(biāo)轉(zhuǎn)動效果”—— 265.com 把它放在網(wǎng)頁的LOGO里,用javascript來實現(xiàn),這個創(chuàng)意不錯! 以前剛做FLASH的時候,用AS1實現(xiàn)過,今天下班早,在家簡寫了個:
    2008-02-02
  • javascript中檢測變量的類型的代碼

    javascript中檢測變量的類型的代碼

    javascript對于變量的定義、類型的要求都比較松散,這樣既方便,但又容易犯錯。有時候進(jìn)行必要的類型檢查是必須的。
    2010-12-12
  • DatePickerDialog 自定義樣式及使用全解

    DatePickerDialog 自定義樣式及使用全解

    這篇文章主要介紹了DatePickerDialog 自定義樣式及使用全解,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • JS獲取一個表單字段中多條數(shù)據(jù)并轉(zhuǎn)化為json格式

    JS獲取一個表單字段中多條數(shù)據(jù)并轉(zhuǎn)化為json格式

    這篇文章主要介紹了JS獲取一個表單字段中多條數(shù)據(jù)并轉(zhuǎn)化為json格式的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • html+css+js實現(xiàn)canvas跟隨鼠標(biāo)的小圓特效源碼

    html+css+js實現(xiàn)canvas跟隨鼠標(biāo)的小圓特效源碼

    這篇文章主要介紹了html+css+js實現(xiàn)canvas跟隨鼠標(biāo)的小圓特效源碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • JS簡單生成兩個數(shù)字之間隨機數(shù)的方法

    JS簡單生成兩個數(shù)字之間隨機數(shù)的方法

    這篇文章主要介紹了JS簡單生成兩個數(shù)字之間隨機數(shù)的方法,涉及javascript數(shù)值運算的相關(guān)技巧,需要的朋友可以參考下
    2016-08-08
  • JS批量替換內(nèi)容中關(guān)鍵詞為超鏈接

    JS批量替換內(nèi)容中關(guān)鍵詞為超鏈接

    本文主要介紹了JS批量替換內(nèi)容中關(guān)鍵詞為超鏈接,避開已存在的鏈接和alt、title中的關(guān)鍵詞的方法。下面跟著小編一起來看下吧
    2017-02-02
  • 淺談Javascript數(shù)組的使用

    淺談Javascript數(shù)組的使用

    這篇文章主要介紹了淺談Javascript數(shù)組的使用的相關(guān)資料,包括數(shù)組的大小,數(shù)組的遍歷以及數(shù)組的一些方法,非常細(xì)致,需要的朋友可以參考下
    2015-07-07

最新評論

波密县| 新乡市| 绵阳市| 宁远县| 汉中市| 皋兰县| 蒙自县| 秭归县| 嘉义县| 定安县| 多伦县| 多伦县| 耿马| 湘潭市| 马鞍山市| 蚌埠市| 安多县| 呼伦贝尔市| 龙山县| 泗洪县| 睢宁县| 南陵县| 留坝县| 鄂州市| 科技| 巴马| 黎城县| 堆龙德庆县| 双辽市| 阳高县| 巍山| 延安市| 喀喇沁旗| 阳山县| 文登市| 南涧| 渑池县| 唐河县| 永善县| 滕州市| 丰城市|