JavaScript學(xué)習(xí)筆記——事件流和事件委托

一、事件流

1、事件冒泡

IE事件流被稱為事件冒泡。例如在div元素中觸發(fā)click事件,其click事件會沿著DOM數(shù)一路向上,在經(jīng)過的每個節(jié)點上依次觸發(fā)直到documen對象?,F(xiàn)代瀏覽器中的事件會一直冒泡到window對象,如圖所示。

image

2、事件捕獲

Netscape Communication團(tuán)隊提出了事件捕獲的事件流。而事件捕獲中,同事件冒泡流區(qū)別在于其click事件是由document元素捕獲,然后沿DOM樹依次向下傳播直達(dá)目標(biāo)元素div,如圖所示。

image

3、DOM事件流

按照規(guī)范事件流分為三個階段:事件捕獲,達(dá)到目標(biāo)和事件冒泡。
1、事件捕獲:當(dāng)某個元素觸發(fā)某個事件,頂層對象document就會發(fā)出一個事件流,隨著dom樹的節(jié)點向目標(biāo)元素節(jié)點流去,直到到達(dá)事件真正發(fā)生的目標(biāo)元素,在這個過程中,事件相應(yīng)的監(jiān)聽函數(shù)是不會被觸發(fā)的
2、事件目標(biāo):當(dāng)?shù)竭_(dá)目標(biāo)元素之后,執(zhí)行目標(biāo)元素該事件相應(yīng)的處理函數(shù),如果沒有綁定監(jiān)聽函數(shù),那就不執(zhí)行
3、事件冒泡:從目標(biāo)元素開始,往頂層元素傳播,途中如果有節(jié)點綁定了相應(yīng)的事件處理函數(shù),這些函數(shù)都會被一次觸發(fā),如果想阻止事件冒泡,可以使用event.stopPropgation()或者event.cancelBubble=true來阻止事件的冒泡傳播

image

4、事件流的阻止


stopPropagation()

//既可以阻止事件冒泡,也可以阻止事件捕獲,也可以阻止處于目標(biāo)階段

stopImmediatePropagation()

//既可以阻止事件冒泡,也可以阻止事件捕獲,還會阻止該元素其他事件的發(fā)生

二、事件綁定和解綁

1、事件綁定

a、html中直接綁定——html中綁定事件叫做內(nèi)聯(lián)綁定事件,不利于分離

b、js中直接綁定——js中直接綁定稱為賦值綁定函數(shù),缺點是只能綁定一次

//事件監(jiān)聽,綁定
target.addEventListener(type, listener[, useCapture])

參數(shù)說明:

1、target表示要監(jiān)聽事件的目標(biāo)對象,可以是一個文檔上的元素DOM本身,Window或者XMLHttpRequest

2、type表示事件類型的字符串

listener為當(dāng)指定的事件類型發(fā)生時被通知到的一個對象

useCapture為設(shè)置事件的捕獲或者冒泡

true為捕獲,false為冒泡(默認(rèn))

3、addEventListener可以給同一個dom元素綁定多個函數(shù),并且執(zhí)行順序按照綁定順序執(zhí)行,且執(zhí)行順序與useCapture無關(guān)

4、給一個dom元素綁定同一個函數(shù),最多只能綁定useCapture類型不同的兩次

5、addEventListener只支持到IE9,為兼容性考慮,在兼容IE8及一下瀏覽器可以用attachEvent函數(shù),和addEventListener函數(shù)表現(xiàn)一樣,但它綁定函數(shù)的this會指向全局

2、事件解綁

a、通過dom的on***屬性設(shè)置的事件,可以用dom.onclick = null來解綁

b、通過addEventListener綁定的事件可以使用removeEventListener來解綁,接受參數(shù)一樣

c、對于使用removeEventListener函數(shù)解綁事件,需要傳入的listener,useCapture和addEventListener完全一致才可以解綁事件

三、事件委托和事件代理

1、事件委托和事件代理的理解

什么是事件委托?它還有一個名字叫事件代理,JavaScript高級程序設(shè)計上講:事件委托就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件,當(dāng)我們需要對很多元素添加事件的時候,可以通過事件添加到他們的父節(jié)點二將時間委托給父節(jié)點來觸發(fā)處理函數(shù)。

2、使用事件委托的優(yōu)點

一般來說,dom需要有事件處理程序,我們都會直接給它設(shè)置事件處理程序就好了,那如果是很多的dom需要添加事件處理呢?比如我們這里有100個li,每個li都有相同的click事件,那么我們會用for循環(huán)的方法來遍歷所有的li,然后給他們添加事件,那么這樣會存在什么問題呢?

在JavaScript中,添加到頁面上的事件處理程序的數(shù)量將直接關(guān)聯(lián)到頁面整體的運(yùn)行性能,因為需要不斷的與dom節(jié)點進(jìn)行交互,訪問dom的次數(shù)越多,引起瀏覽器重繪與重排的次數(shù)就越多,就會延長整個頁面交互就緒時間,這就是為什么性能優(yōu)化的主要思想是減少dom操作的原因,如果使用事件委托,就會將所有的操作放到j(luò)s程序里面,與dom的操作就只需要交互一次,這樣就能大大的減少與dom的交互次數(shù),提高性能。

每個函數(shù)都是一個對象,是對象就會占用內(nèi)存,內(nèi)存占用率就越大,自然性能就差了,比如上面的100個li,就要占用100個內(nèi)存空間,如果是1000個,10000個呢,如果使用事件委托,那么我們就可以只對它的父級這一個對象(如果只有一個父級)進(jìn)行操作,這樣我們就需要一個內(nèi)存空間就夠了,是不是省了很多,自然性能就會更好。

3、事件委托的原理實現(xiàn)

事件委托是利用事件的冒泡機(jī)制來實現(xiàn)的,Event對象提供了一個屬性叫target,可以返回事件的目標(biāo)節(jié)點,我們稱為事件源,也就是說,target就可以表示為當(dāng)前事件操作的dom,但是不是真正操作的dom。標(biāo)準(zhǔn)瀏覽器用event.target,此時知識獲取了當(dāng)前節(jié)點的位置,并不知道是什么節(jié)點名稱,這里我們用nodeName來獲取具體是什么標(biāo)簽名,這個返回的是一個大寫的,一般轉(zhuǎn)化為小寫再進(jìn)行比較

如果你想將事件委托給父元素來處理,但每個子元素的事件內(nèi)容又不相同時,這里我們可以給每個子元素添加一個唯一的key來作標(biāo)識,然后在父元素中對其進(jìn)行分別的處理,例如:


const list = document.querySelector('#list)

const lists = list.querySelector('#list > li')for(let i=0; i<lists.length; i++){

    lists[i].dataset.key = 'list-' + i

}

list.addEventListener('click',function(e){

    const event = e || window.event

    const target = event.target || event.srcElement 

    if(target.nodeName.toLocaleLowerCase() === 'li'){

        switch(target.dataset.key){

            case 'list-1':

                do something-1

                break            
            case 'list-2':

                do something-2

                break           

            default:

                do something-3

                break        }

    }

}) 

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容