一步步學習javascript基礎篇(8):細說事件


終於學到事件了,不知道為何聽到“事件”就有一種莫名的興奮。可能是之前的那些知識點過於枯燥無味吧,說起事件感覺頓時高大上了。今天我們就來好好分析下這個高大上的東西。

可以說,如果沒有事件我們的頁面就只能閱讀了。有了事件,我們可以通過鍵盤或是鼠標和頁面交互了,通過我們不同的操作頁面給出不同的響應。好了,開始我們今天的分析吧。

DOM0級事件處理方式

什么是DOM0級?

其實世上本來沒有DOM0級,叫的人多了就有了DOM0級。

在1998 年 10 月 DOM1級規范成為 W3C 的推薦標准,在此之前的實現我們就習慣稱為DOM0級,其實本是沒有這個標准的。

<input type="button" value="but" id="but" />
<script type="text/javascript">
    document.getElementById("but").onclick = function () {
        alert("點擊了按鈕1");
    }
    document.getElementById("but").onclick = function () {
        alert("點擊了按鈕2");
    } 
</script>

上面代碼,我們發現點擊按鈕時,僅僅只彈出了“點擊了按鈕2”。上一個定義的方法被覆蓋了。這種會覆蓋上一次事件定義的方式我們稱為DOM0級事件。

如果我們使用Jquery來添加事件的話:

<script src="../Scripts/jquery-1.8.2.js"></script>
<input type="button" value="but" id="but" />
<script type="text/javascript">
    $("#but").click(function () {
        alert("點擊了按鈕1");
    });
    $("#but").click(function () {
        alert("點擊了按鈕2");
    });

我們會發現依次彈出了“點擊了按鈕1”,“點擊了按鈕2”,這是怎么做到的?為什么沒有覆蓋上一次的定義,我猜應該是使用到了DOM2級事件機制。(我沒有看過Jquery的源碼,暫時還看不懂)。

DOM2級事件處理方式

<input type="button" value="but" id="but" />
<script type="text/javascript">      
    document.getElementById("but").addEventListener("click", function () {
        alert("點擊了按鈕1");
    });
    document.getElementById("but").addEventListener("click", function () {
        alert("點擊了按鈕2");
    });        
</script>

如此通過元素對象的addEventListener添加的方法就是2級事件。這里需要注意,與0級事件不同的是事件名前面不能帶“on”了。點擊按鈕彈出的結果和前面的Jquery添加方式一樣。

有人可能要問了,怎么沒有DOM1級事件。我能說的是沒有就是沒有,沒有為什么。在確定DOM1級標准的時候不需要擴展事件定義機制,DOM0級的事件就夠用了。

我們剛才通過2級事件添加了方法,那么如果我們想要刪除其中的一個怎么辦。如果是上面的那種匿名方法,我可以很明確的告訴你沒辦法移除。下面我們來說說可以移除的添加方式吧:

<input type="button" value="but" id="but" />
<script type="text/javascript">      
    document.getElementById("but").addEventListener("click", fun1);//給click事件添加方法fun1
    document.getElementById("but").addEventListener("click", fun2);//給click事件添加方法fun2

    function fun1() {
        alert("點擊了按鈕1");
    }
    function fun2() {
        alert("點擊了按鈕2");
    }

    document.getElementById("but").removeEventListener("click", fun1);//給click事件移除方法fun1
</script>

如此就通過removeEventListener方法進行移除操作了。

以上只是DOM2級的標准實現,當然除了IE這個怪胎非得當攪屎棍。在IE下,有同效的實現函數:

<input type="button" value="but" id="but" />
<script type="text/javascript">      
    document.getElementById("but").attachEvent("onclick", fun1, false);//給click事件添加方法fun1
    document.getElementById("but").attachEvent("onclick", fun2, false);//給click事件添加方法fun2

    function fun1() {
        alert("點擊了按鈕1");
    }
    function fun2() {
        alert("點擊了按鈕2");
    }

    document.getElementById("but").detachEvent("onclick", fun1);//給click事件移除方法fun1

注意:attachEvent() 和 detachEvent() 替換了addEventListener()和removeEventListener(),且第一個參數是事件名前面加了"on"。

DOM3級事件

可能有人覺得很奇怪,哪來的DOM3級事件啊。其實上面我們說的DOM0級和DOM2級事件說的是事件的處理方式而已,而這里說的DOM3級事件是說的在DOM3級中新增的一些事件。

至於DOM1級事件,那我就真的沒聽過。

DOM3級事件是在DOM2級事件的基礎上重新定義了或是新增了某些事件。如鼠標事件:

DOM2有,click、mousedown、mousemove、mouseout、mouseover、mouseup
而DOM3級中卻有,click、dblclick、mousedown、mouseenter、mouseleave、mousemove、mouseout、mouseover、mouseup

(其中dblclick、mouseenter、mouseleave是DOM3中新增的)
DOM3級事件實現方式可以用DOM0和DOM2級中的方式,只是新增了寫事件類型。這里就不一一列舉了。

事件冒泡

什么是事件冒泡?我們先來看個例子。

<div onclick="divfun();" style="border:1px dashed red;padding:50px">
    <span onclick="spanfun();" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input type="button" value="but" onclick="butfun();" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    function butfun() {
        alert("按鈕被點擊了");
    }
    function spanfun() {
        alert("span被點擊了");
    }
    function divfun() {
        alert("div被點擊了");
    }
</script>

一個div包了一個span,然后span里面包了一個button。我們在點擊按鈕的時候會先觸發按鈕事件,然后觸發span的點擊事件,然后觸發div的點擊事件。這就是事件冒泡。(使用DOM0級事件默認是事件冒泡方式

效果圖:

示意圖:

事件捕獲

什么是事件捕獲?其實就是事件冒泡的逆向。

那我們怎么實現這個效果呢?我們可以通過DOM2級事件。上面我們已經簡單的講解過了DOM2級事件的實現方式

通過addEventListener和removeEventListener給事件添加和刪除函數。上面我們講addEventListener的時候如果你再回頭看看,我們只給了兩個參數,第一個是事件名,第二個是要添加的方法,其實還有第三個參數一個布爾值用來表示事件流方向(true為事件捕獲方向,false為事件冒泡方向)。那么我們完全可以通過DOM2級事件來實現事件捕獲的效果,如:

<div id="mydiv" style="border:1px dashed red;padding:50px">
    <span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    document.getElementById("mydiv").addEventListener("click", divfun, true);
    document.getElementById("mysapn").addEventListener("click", spanfun, true);
    document.getElementById("mybut").addEventListener("click", butfun, true);

    function butfun() {
        alert("按鈕被點擊了");
    }
    function spanfun() {
        alert("span被點擊了");
    }
    function divfun() {
        alert("div被點擊了");
    }
</script>

效果圖:

同樣,我們也可以通過DOM2級事件實現事件冒泡,就上面的代碼僅僅只需要把addEventListener的第三那個參數改成false就可以了,有興趣的同學可以自己試試。

然后IE這個攪屎棍又開始不服了,我就不實現事件捕獲你能把我怎么着。IE中等效實現的attachEvent的根本就沒給第三個參數,所以為了兼容,我們一般只用事件冒泡(IE只支持事件冒泡)。

事件冒泡的使用

  • 取消事件冒泡

通過上面,我們知道只要點擊了按鈕,那么按鈕的上層元素中的點擊事件都會觸發。那我們會想如果我TM就只想點擊某個元素的時候才 觸發,不想讓它往上冒怎么辦,請看下面:

<div id="mydiv" style="border:1px dashed red;padding:50px">
    <span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    //第三個參數是false,那么就是事件冒泡了
    document.getElementById("mydiv").addEventListener("click", divfun, false);
    document.getElementById("mysapn").addEventListener("click", spanfun, false);
    document.getElementById("mybut").addEventListener("click", butfun, false);

    function butfun(event) {
        event.stopPropagation();//在點擊按鈕時,取消事件冒泡
        alert("按鈕被點擊了");
    }
    function spanfun() {
        //這里沒有取消事件冒泡,所以點擊span的時候還是會繼續冒泡到div
        alert("span被點擊了");
    }
    function divfun() {
        alert("div被點擊了");
    }
</script>

效果圖:

您如果仔細看了效果圖,那么你會發現。點擊按鈕的時候並沒有冒泡,而點擊span的時候還是冒泡了。那是因為我們代碼里面在按鈕事件的方法里面加了 event.stopPropagation()//取消冒泡 。

  • 事件委托

既然可以如此,我們可以在每個事件方法里面都加上取消冒泡,那么所有的元素都只實現自己的事件對應的方法了。我們發現這個事件冒泡反而把事情搞麻煩了,好好的一個元素對應一個事件干嘛要冒泡啊,還要手動去取消冒泡。既然有這個東西,它總是有它的作用的。我們看到上面我們定義事件方法時,取到了每個元素,然后給每個元素定義方法。那我們可以通過事件冒泡定義一個方法來實現嗎,先看看下面的代碼:

<div id="mydiv" style="border:1px dashed red;padding:50px">
    <span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    //第三個參數是false,那么就是事件冒泡了
    document.getElementById("mydiv").addEventListener("click", divfun, false);   function divfun(event) {
        var targetID = event.target.id 
        if (targetID == "mybut") {
            alert("按鈕被點擊了");
        } else if (targetID == "mysapn") {
            alert("span被點擊了"); 
        } else if (targetID == "mydiv") {
            alert("div被點擊了"); 
        } 
    }
</script>

 

效果圖:

仔細觀察的你,會發現我們點擊每個元素會觸發對應消息。這就是我們上面為每個元素添加方法然后取消冒泡同樣的效果。那么我們再來分析下實現代碼,會發現這里反而是使用了冒泡。

 event.target//返回事件的目標節點(觸發該事件的節點)  var targetID = event.target.id //返回事件的目標節點的id(觸發該事件的節點的Id) 

因為我們為最外面的div添加了事件的方法,所以我們在點擊按鈕的時候會依次觸發按鈕、span、div的點擊事件,然按鈕和span都沒有定義事件方法,所以不管是點擊按鈕、span還是div都會冒泡到div的點擊事件,然后我們就可以根據上面的target屬性來得知到底是由那個節點觸發的。請看示意圖:

有人會這,這么麻煩有什么好處呢?我們仔細看看這個通過冒泡實現的個節點點擊事件,你有沒有發現我們僅僅只是通過getElementById取了一個最外層的div元素,且我們也僅僅只用了一個方法(雖然方法里面的邏輯會更加復雜點)。這只是3個元素,如果有30個呢?甚至上百個呢?我們只定義最外層的元素,這樣就減少了大量的DOM引用了(這樣就直接減少了檢索元素需要花的時間),同時也可以減少內存的占用。直接提升了性能。(雖然很多時候我們不會這樣來定義事件,我自己就很少這樣來定義事件,可能是習慣問題吧。>_<

 

這是學習記錄,不是教程。文中錯誤難免,您可以指出錯誤,但請不要言辭刻薄。

原文首鏈:http://www.haojima.net/zhaopei/531.html

本文已同步至目錄索引:一步步學習javascript

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM