Day 52/100 JavaScript事件模型

寫在前面的話

被玖富的面試官,問到的,只知道大概的我,當(dāng)時(shí)尷尬極了...

好記性不如爛筆頭,腦子越來越不可靠

(一)觀察者模式

觀察者模式又叫做發(fā)布訂閱者模式(Publish/Subscribe),它可以讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,這個(gè)主題對(duì)象的狀態(tài)變化時(shí)會(huì)通知所有的訂閱者,使得它們能夠做出反應(yīng)。

JS的事件模型就是一種觀察者模式的體現(xiàn),當(dāng)對(duì)應(yīng)的事件被觸發(fā)時(shí),監(jiān)聽該事件的所有監(jiān)聽函數(shù)都會(huì)被調(diào)用。


(二)事件與事件流

事件是與瀏覽器或文檔交互的瞬間,如點(diǎn)擊按鈕,填寫表格等,它是JS與HTML之間交互的橋梁。

DOM是樹形結(jié)構(gòu),如果同時(shí)給父子節(jié)點(diǎn)都綁定事件時(shí),當(dāng)觸發(fā)子節(jié)點(diǎn)的時(shí)候,這兩個(gè)事件的發(fā)生順序如何決定?這就涉及到事件流的概念,它描述的是頁面中接受事件的順序。

事件流有兩種:

事件冒泡(Event Bubbling): 是一種從下往上的傳播方式。事件最開始由最具體的元素(文檔中嵌套層次最深的那個(gè)節(jié)點(diǎn)接受, 也就是DOM最低層的子節(jié)點(diǎn)), 然后逐漸向上傳播到最不具體的那個(gè)節(jié)點(diǎn),也就是DOM中最高層的父節(jié)點(diǎn)。

事件捕獲(Event Capturing): 與事件冒泡相反。事件最開始由不太具體的節(jié)點(diǎn)最早接受事件, 而最具體的節(jié)點(diǎn)最后接受事件。


(三)事件模型

1、DOM 0級(jí)模型

又稱為原始事件模型,在該模型中,事件不會(huì)傳播,即沒有事件流的概念。事件綁定監(jiān)聽函數(shù)比較簡(jiǎn)單, 有兩種方式:

HTML代碼中直接綁定:

<input type="button" onclick="fun()">

通過JS代碼指定屬性值:

varbtn = document.getElementById('.btn');

btn.onclick =fun;

移除監(jiān)聽函數(shù):

btn.onclick?=?null;

這種方式所有瀏覽器都兼容,但是邏輯與顯示并沒有分離。

2、IE事件模型

IE事件模型共有兩個(gè)過程:

事件處理階段(target phase)。事件到達(dá)目標(biāo)元素, 觸發(fā)目標(biāo)元素的監(jiān)聽函數(shù)。

事件冒泡階段(bubbling phase)。事件從目標(biāo)元素冒泡到document, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。

事件綁定監(jiān)聽函數(shù)的方式如下:

attachEvent(eventType, handler)

事件移除監(jiān)聽函數(shù)的方式如下:

detachEvent(eventType, handler)

參數(shù)說明:

eventType指定事件類型(注意加on)

handler是事件處理函數(shù)

3、DOM2級(jí)模型

屬于W3C標(biāo)準(zhǔn)模型,現(xiàn)代瀏覽器(除IE6-8之外的瀏覽器)都支持該模型。在該事件模型中,一次事件共有三個(gè)過程:

事件捕獲階段(capturing phase)。事件從document一直向下傳播到目標(biāo)元素, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。

事件處理階段(target phase)。事件到達(dá)目標(biāo)元素, 觸發(fā)目標(biāo)元素的監(jiān)聽函數(shù)。

事件冒泡階段(bubbling phase)。事件從目標(biāo)元素冒泡到document, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。

事件綁定監(jiān)聽函數(shù)的方式如下:

addEventListener(eventType, handler, useCapture)

事件移除監(jiān)聽函數(shù)的方式如下:

removeEventListener(eventType, handler, useCapture)


4、事件對(duì)象

當(dāng)一個(gè)事件被觸發(fā)時(shí),會(huì)創(chuàng)建一個(gè)事件對(duì)象(Event Object), 這個(gè)對(duì)象里面包含了與該事件相關(guān)的屬性或者方法。該對(duì)象會(huì)作為第一個(gè)參數(shù)傳遞給監(jiān)聽函數(shù)。

DOM事件模型中的事件對(duì)象常用屬性:

type用于獲取事件類型

target獲取事件目標(biāo)

stopPropagation()阻止事件冒泡

preventDefault()阻止事件默認(rèn)行為

IE事件模型中的事件對(duì)象常用屬性:

type用于獲取事件類型

srcElement獲取事件目標(biāo)

cancelBubble阻止事件冒泡

returnValue阻止事件默認(rèn)行為

5、Event Wrapper

由于事件模型的差異以及Event對(duì)象的不同,為了達(dá)到兼容各個(gè)瀏覽器的目的,我們可以增加一個(gè)Event Wrapper, 它對(duì)各個(gè)瀏覽器應(yīng)當(dāng)提供一致的事件操作接口。

6、事件代理

事件在冒泡過程中會(huì)上傳到父節(jié)點(diǎn),因此可以把子節(jié)點(diǎn)的監(jiān)聽函數(shù)定義在父節(jié)點(diǎn)上,由父節(jié)點(diǎn)的監(jiān)聽函數(shù)統(tǒng)一處理多個(gè)子元素的事件,這種方式稱為事件代理(Event delegation)。

我們有一個(gè)div元素,它包含三個(gè)按鈕:

<div id="box">

? ? <input type="button" value="按鈕" id="btn">

? ? <input type="button" value="按鈕2" id="btn2">

? ? <input type="button" value="按鈕3" id="btn3">

</div>

我們可以在父節(jié)點(diǎn)上一次性的為所有子節(jié)點(diǎn)注冊(cè)監(jiān)聽函數(shù):

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

box.addEventListener('click', function(event) {

? if (event.target.tagName.toLowerCase() === 'input') {

? ? // some code

? }

});

7、JQuery Event模型

JQuery解決的一個(gè)主要問題就是瀏覽器的兼容問題,它有自己的事件模型實(shí)現(xiàn)方式。它主要有以下特性:

重定義了JQuery.Event對(duì)象, 統(tǒng)一了事件屬性和方法, 統(tǒng)一了事件模型

可以在一個(gè)事件類型上添加多個(gè)事件處理函數(shù), 可以一次添加多個(gè)事件類型的事件處理函數(shù)

支持自定義事件(事件命名空間)

提供了toggle, hover組合事件

提供了one, live-die, delegate-undelegate

提供了統(tǒng)一的事件封裝, 綁定, 執(zhí)行, 銷毀機(jī)制

$(document).ready();

....


參考資料

http://www.itdecent.cn/p/30d6b4258508

https://segmentfault.com/a/1190000006934031

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

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