1. 程式人生 > >JS學習筆記——事件

JS學習筆記——事件

1.事件流

當我們點選網頁上的某一個元素時,觸發的動作不僅僅跟這個元素有關,還跟包含這個元素的所有上層容器有關。觸發事件流的流動有一個先後順序,目前有兩種:1.IE所提出的事件冒泡;2.Netscape所提出的事件捕獲。
DOM事件流則是綜合了前面兩種事件流,先捕獲再冒泡。現代瀏覽器大多支援DOM事件流。



2.事件處理程式

為元素繫結相應的事件處理程式有3種方法:HTML、DOM0級、DOM2級。事件處理程式以”on”開頭,如”click”事件的處理程式是”onclick()”。

2.1 HTML事件處理

我們把事件處理程式當做html的元素屬性加入html標籤中。這種方法的最大缺點就是html和js緊耦合。

<input type="button" value="button" onclick="alert(`Click Me`)" />
<input type="button" value="button" onclick="test()" />

<script>
function test() {
    //...
}
</script>

2.2 DOM0級事件處理

通過DOM操作獲取元素,元素都帶有事件處理(比如onclik())的屬性,我們把函式賦值給該屬性即可。在事件處理程式中,this指向給呼叫該事件處理程式的元素(在事件委託中,this就指向那個儘量高層次的元素)。若想刪除事件處理程式,將該屬性賦值null即可。DOM0級繫結的事件處理程式會發生在冒泡階段。

var p = document.getElementById('p');
p.onclick = function() {
    alert(this.id);//p
}
p.onclick = null;//刪除繫結的事件處理程式

2.3 DOM2級事件處理

DOM2級事件處理程式的功能比DOM0級更加豐富。DOM2級可以一個事件新增多個處理程式,還可以指定程式在冒泡階段呼叫還是捕獲階段呼叫。DOM2級要刪除處理程式,需要傳入新增函式時的那個函式引數,這就說明,新增的匿名函式無法刪除。

var p = document.getElementById('p');
p.addEventListener("click"
, function(){ alert(this.id);//p }, false);//第三個引數 true:捕獲階段呼叫;false:冒泡階段呼叫; //該移除函式沒有起作用 p.removeEventListener("click", function(){ alert(this.id); }, false);

2.4 IE事件處理

雖然IE9也支援DOM2級事件處理程式(DOM事件流),但在IE9以前,是隻支援IE事件處理(IE事件流)的。IE事件流是事件冒泡。IE事件處理程式與DOM2級事件處理程式非常相似。IE事件處理只支援兩個引數,第三個引數無法選擇捕獲還是冒泡。在IE8以及更早版本中,只支援冒泡。與DOM2級不同的是,這裡的this指向全域性window。
這裡我們注意,並不是所有IE瀏覽器都是IE事件處理(IE事件流),像IE9就支援DOM事件流,支援DOM事件流,也支援DOM2級事件處理程式。

var p = document.getElementById('p');

p.attachEvent("onclick", function(){//注意這裡是"onclick",而不是DOM2級的"click"
    alert(this === window);//true
});

//與DOM2級一樣,匿名函式無法被刪除
p.detachEvent("onclick", function(){
    alert(this === window);//true
});

3.DOM事件物件

事件物件分為DOM事件物件和IE事件物件,IE就是個奇葩的存在,除了IE之外,其他瀏覽器都是DOM事件物件。
事件處理程式會接收一個事件物件,該事件物件中有許多跟事件有關的屬性,比如type、churentTarget、target等。
下面我們區分一下三個容易混淆的屬性thistargetcurrentTarget。this始終等於currentTarget,這兩個又等於呼叫處理程式的元素。target等於動作真實發生的物件。

<body>
    <div id='div'>
        <p id='p'>hello!</p>
    </div>
</body>

//div是p的父元素,如果點選p,event.target就是p
//如果點選div其他地方(不是p),event.target就是div
div.detachEvent("onclick", function(event){
    //event.type == "click"
    alert(this === div);//true
    alert(event.currentTarget === div);//true
    alert(event.target === p);//true
});

4.事件代理(事件委託)

如果我們有許多的元素需要繫結事件處理程式,按照上面的方法:先使用DOM獲取元素,再給元素繫結函式。這種方法會使得web效能下降:DOM操作耗時;函式的本質是物件,耗記憶體。
這種場景的解決方法就是使用事件代理,即利用事件冒泡,給儘量高層次的元素繫結一個事件,在這個事件中,根據事件物件的屬性來做相應的處理。

div.onclick = function(event) {
    switch(event.target.id) {
        case 'p':
            alert('p');
            break;
        case 'div':
            alert('div');
            break;
    }
}