摘要:事件監(jiān)聽(tīng)器可以被添加到節(jié)點(diǎn)上并在給定事件發(fā)生時(shí)觸發(fā)。可以選擇觸發(fā)階段冒泡捕獲事件機(jī)制標(biāo)準(zhǔn)事件標(biāo)準(zhǔn)規(guī)定事件流包含三個(gè)階段,分別為事件捕獲階段,目標(biāo)階段,事件冒泡階段。返回其事件監(jiān)聽(tīng)器觸發(fā)該事件的元素。清理事務(wù)設(shè)置檢查點(diǎn)的標(biāo)志為。
前端最基礎(chǔ)的就是 HTML+CSS+Javascript。掌握了這三門技術(shù)就算入門,但也僅僅是入門,現(xiàn)在前端開(kāi)發(fā)的定義已經(jīng)遠(yuǎn)遠(yuǎn)不止這些。前端小課堂(HTML/CSS/JS),本著提升技術(shù)水平,打牢基礎(chǔ)知識(shí)的中心思想,我們開(kāi)課啦(每周四)。
前面我們已經(jīng)基本掌握常規(guī)的語(yǔ)法語(yǔ)義,以及基本的使用方法。接下來(lái)我們講深入進(jìn)去了解其中內(nèi)在的原理。
今天我們要講什么?事件機(jī)制
事件對(duì)象(Event)
event loop
DOM (與事件的關(guān)系,看不看無(wú)所謂)DOM(Document Object Model——文檔對(duì)象模型)是用來(lái)呈現(xiàn)以及與任意 HTML 或 XML文檔交互的 API。DOM 是載入到瀏覽器中的文檔模型,以節(jié)點(diǎn)樹(shù)的形式來(lái)表現(xiàn)文檔,每個(gè)節(jié)點(diǎn)代表文檔的構(gòu)成部分(例如:頁(yè)面元素、字符串或注釋等等)。
DOM 是萬(wàn)維網(wǎng)上使用最為廣泛的 API 之一,因?yàn)樗试S運(yùn)行在瀏覽器中的代碼訪問(wèn)文件中的節(jié)點(diǎn)并與之交互。節(jié)點(diǎn)可以被創(chuàng)建,移動(dòng)或修改。事件監(jiān)聽(tīng)器可以被添加到節(jié)點(diǎn)上并在給定事件發(fā)生時(shí)觸發(fā)。
DOM 并不是天生就被規(guī)范好了的,它是瀏覽器開(kāi)始實(shí)現(xiàn)JavaScript時(shí)才出現(xiàn)的。這個(gè)傳統(tǒng)的 DOM 有時(shí)會(huì)被稱為 DOM 0。現(xiàn)在, WHATWG 維護(hù)DOM現(xiàn)存標(biāo)準(zhǔn)。
-- MDN
既然 DOM 有版本,那么在他的環(huán)境上事件的支持也是有版本的。文檔
DOM 事件(0 級(jí))body.onclick 這種定義方式的。
不可以多次監(jiān)聽(tīng)事件,因?yàn)槭琴x值的方式,下次賦值會(huì)覆蓋。
只可以在冒泡階段觸發(fā)
DOM 事件(2 級(jí))addEventListener 方式定義的。
可以多次監(jiān)聽(tīng),切按監(jiān)聽(tīng)順序執(zhí)行回調(diào)(有序)
取消監(jiān)聽(tīng)需要同一引用的函數(shù)。舉個(gè)栗子
// 錯(cuò)誤案例,兩個(gè)方法不是同一引用,導(dǎo)致清除不掉 document.addEventListener("click", function(){}) document.removeEventListener("click", function(){}) // 正確案例,同一引用,可以清除。 function documentClick(){} document.addEventListener("click", documentClick) document.removeEventListener("click", documentClick)
可以選擇觸發(fā)階段(冒泡&捕獲) capture
事件機(jī)制標(biāo)準(zhǔn)事件:EMCAScript 標(biāo)準(zhǔn)規(guī)定事件流包含三個(gè)階段,分別為事件捕獲階段,目標(biāo)階段,事件冒泡階段。
先存?zhèn)€代碼,之后的例子我們用這個(gè)例子。測(cè)試看我這里的 DEMO
click事件捕獲階段
捕獲階段:由外到內(nèi),觸發(fā)規(guī)律為 html > body > a。
如果想在捕獲階段就觸發(fā),需要傳入?yún)?shù) {capture: true}
冒泡階段:由內(nèi)到外,觸發(fā)規(guī)律為 a > body > html
這個(gè)階段執(zhí)行是 W3C 默認(rèn)的,等價(jià)于 {capture: false}
圖片來(lái)源-https://www.w3.org/TR/DOM-Lev...
事件的捕獲階段 > 處于目標(biāo)階段 > 事件的冒泡階段 > 事件的默認(rèn)行為
這里為什么要強(qiáng)調(diào)這個(gè)順序呢?
因?yàn)槟J(rèn)行為是在最后面,所以我們都可以用 e.preventDefault() 來(lái)阻止。
基于上條的阻止默認(rèn)事件。在移動(dòng)端滑動(dòng)時(shí),阻止默認(rèn)事件需要手動(dòng)設(shè)置 passive 為 false。
passive: Boolean,設(shè)置為 true 時(shí),表示 listener 永遠(yuǎn)不會(huì)調(diào)用 preventDefault()。如果 listener 仍然調(diào)用了這個(gè)函數(shù),客戶端將會(huì)忽略它并拋出一個(gè)控制臺(tái)警告。
我們真正單擊的元素的事件觸發(fā)不在冒泡和捕獲階段,而在目標(biāo)階段觸發(fā)。 DEMO-冒泡&捕獲階段觸發(fā)事件,可以看到,他是通過(guò)定義時(shí)的先后順序來(lái)觸發(fā)的。
事件對(duì)象(Event)Event 對(duì)象--mdn
事件對(duì)象(屬性&方法)key | 類型 | 描述 |
---|---|---|
bubbles | boolean | 是否冒泡 |
cancelable | boolean | 是否可以取消的默認(rèn)動(dòng)作。 |
currentTarget | Element | 返回其事件監(jiān)聽(tīng)器觸發(fā)該事件的元素。(this 的真實(shí)指向) |
eventPhase | Intenger | 返回事件傳播的當(dāng)前階段 |
target | Element | 返回觸發(fā)此事件的元素。(事件的目標(biāo)節(jié)點(diǎn)) |
timeStamp | Date | 觸發(fā)的時(shí)間戳 |
type | String | 事件名稱。 |
isTrusted | boolean | 該事件是否是瀏覽器生成(true 代表是,false 代表是開(kāi)發(fā)人員創(chuàng)建 |
preventDefault | Function | 取消事件的默認(rèn)行為在 cancelable=true 時(shí)有效 |
stopPropagation | Function | 取消事件的捕獲或者冒泡行為在 bubbles=true 時(shí)有效 |
IE: event.cancelBubble=true; //阻止事件冒泡
IE: event.returnValue=false; //阻止事件的默認(rèn)行為
獲取事件 window.event
事件類型(分類、Event對(duì)象之類)DOM event 子類,根據(jù)不同的事件類型,返回的對(duì)象會(huì)有些許不同,比如 Mouse 類型的,就會(huì)有單擊坐標(biāo)之類的。 KeyboardEvent 之類的就會(huì)有按鍵之類的。
new 一個(gè)事件對(duì)象CustomEvent() --mdn
document.body.onclick=function(e){console.log(e)} var btn=document.body; var event= new CustomEvent("click"); btn.dispatchEvent(event);
其實(shí)這里我們可以自定義事件的名稱,然后我們就可以實(shí)現(xiàn)一個(gè)發(fā)布訂閱的功能。
document.addEventListener("bus", function(e) { console.log(e, e.detail) }); var event = new CustomEvent("bus", {detail: {LN_type: "lilnong.top"}}); document.dispatchEvent(event);event loop (事件循環(huán))
首先,我們要牢記一件事情 js 是單線程
Event Loop 中文叫事件循環(huán)。是瀏覽器內(nèi)部的一種機(jī)制,javaScript 單線程運(yùn)行時(shí)如何不阻塞 UI。
Javascript 有一個(gè) main thread 主線程和 call-stack 調(diào)用棧(執(zhí)行棧),所有的任務(wù)都會(huì)被放到調(diào)用棧(棧采用的是后進(jìn)先出的規(guī)則)等待主線程執(zhí)行。
在 JavaScript 中,任務(wù)被分為兩種,一種宏任務(wù)(MacroTask)也叫Task,一種叫微任務(wù)(MicroTask)。
MacroTask(宏任務(wù))、setTimeout、setInterval、setImmediate、I/O、UI Rendering。
異步任務(wù)會(huì)在有了結(jié)果后,將注冊(cè)的回調(diào)函數(shù)放入任務(wù)隊(duì)列中等待主線程空閑的時(shí)候(調(diào)用棧被清空),被讀取到棧內(nèi)等待主線程的執(zhí)行。
Process.nextTick(Node獨(dú)有)、Promise、MutationObserver
每個(gè)宏任務(wù)執(zhí)行完畢后,會(huì)檢查 microTask 隊(duì)列是否有回調(diào),會(huì)按照先入先出的規(guī)則執(zhí)行,都執(zhí)行完再執(zhí)行宏任務(wù),如此循環(huán)。
棧采用的是后進(jìn)先出的規(guī)則,這里我們調(diào)用 a(),a() 內(nèi)部會(huì)調(diào)用 aa(), aa() 內(nèi)部又調(diào)用 aa()。
function a(){return aa()} function aa(){return aaa()} function aaa(){return 1}
a 進(jìn)棧
aa 進(jìn)棧
aaa 進(jìn)棧
aaa 出棧
...
事件循環(huán)的進(jìn)程模型選擇任務(wù)隊(duì)列中最先進(jìn)入的任務(wù),如果任務(wù)隊(duì)列為空,則執(zhí)行跳轉(zhuǎn)到微任務(wù)(MicroTask)的執(zhí)行步驟
任務(wù)設(shè)置為已選擇任務(wù)
執(zhí)行任務(wù)
任務(wù)設(shè)置為空
運(yùn)行完成的任務(wù)從任務(wù)隊(duì)列中刪除
MicroTasks 步驟:
進(jìn)入 MicroTask 檢查點(diǎn)
設(shè)置 MicroTask 檢查點(diǎn)標(biāo)志為 true
當(dāng)事件循環(huán) MicroTask 不為空時(shí):
選擇最先進(jìn)入隊(duì)列的任務(wù),
設(shè)置為已選擇的任務(wù)
運(yùn)行
將已經(jīng)執(zhí)行完成的 MicroTask 改變狀態(tài)
移出 MicroTask。
清理IndexDB事務(wù)
設(shè)置 MicroTask 檢查點(diǎn)的標(biāo)志為false。
更新界面渲染。
返回第一步。
舉個(gè)栗子(常問(wèn)無(wú)聊題)console.log("script start"); setTimeout(function() { console.log("setTimeout"); }, 0); new Promise(function(reslove){ console.log("Promise-start") reslove(); }).then(function() { console.log("Promise-end"); }) console.log("script end");
結(jié)構(gòu)應(yīng)該沒(méi)錯(cuò)
任務(wù)入棧(代碼塊)
console.log("script start"); 棧中,同步代碼,直接輸出
function() {console.log("setTimeout");} 入 MacroTask
new Promise 同步代碼,執(zhí)行
入棧 function(reslove){console.log("Promise-start");reslove();}
執(zhí)行 console.log("Promise-start");
出棧
.then(function() {console.log("Promise-end");}) 進(jìn) MicroTask
console.log("script end"); 同步代碼,輸出
當(dāng)前執(zhí)行完出棧,判斷 MicroTasks
執(zhí)行 console.log("Promise-end");
完成所有 MicroTasks
渲染 UI
MacroTasks是否有數(shù)據(jù)?
執(zhí)行 MacroTasks 中第一個(gè)。
console.log("setTimeout"); 輸出。
異步事件(消息)DOM 事件
setTimeout
XHR
Promise
總結(jié)
事件機(jī)制
當(dāng)前執(zhí)行塊
當(dāng)前執(zhí)行塊的微任務(wù)隊(duì)列
宏任務(wù)隊(duì)列
Event 事件級(jí)別
addEventListener 要主要保存 function 的引用,用于解綁
隊(duì)列,先進(jìn)先出(想起了梗,吃多了拉)
堆棧,先進(jìn)后出(想起了梗,吃多了吐)
觸發(fā)階段 捕獲>目標(biāo)>冒泡
Event 對(duì)象,針對(duì)不同的類型,有自己獨(dú)特的屬性。
微信公眾號(hào):前端linong 初級(jí)階段文章目錄前端培訓(xùn)-初級(jí)階段(17) - 數(shù)據(jù)存儲(chǔ)(cookie、session、stroage)
前端培訓(xùn)-初級(jí)階段(13) - 正則表達(dá)式
前端培訓(xùn)-初級(jí)階段(13) - 類、模塊、繼承
前端培訓(xùn)-初級(jí)階段(13) - ECMAScript (內(nèi)置對(duì)象、函數(shù))
前端培訓(xùn)-初級(jí)階段(13) - ECMAScript (語(yǔ)法、變量、值、類型、運(yùn)算符、語(yǔ)句)
前端培訓(xùn)-初級(jí)階段(13、18)
前端培訓(xùn)-初級(jí)階段(9 -12)
前端培訓(xùn)-初級(jí)階段(5 - 8)
前端培訓(xùn)-初級(jí)階段(1 - 4)
資料前端培訓(xùn)目錄、前端培訓(xùn)規(guī)劃、前端培訓(xùn)計(jì)劃
JavaScript系列----事件機(jī)制
事件參考--mdn
tasks-microtasks-queues-and-schedules
一次弄懂Event Loop(徹底解決此類面試問(wèn)題) --光光同學(xué)-juejin
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/104812.html
摘要:事件監(jiān)聽(tīng)器可以被添加到節(jié)點(diǎn)上并在給定事件發(fā)生時(shí)觸發(fā)。可以選擇觸發(fā)階段冒泡捕獲事件機(jī)制標(biāo)準(zhǔn)事件標(biāo)準(zhǔn)規(guī)定事件流包含三個(gè)階段,分別為事件捕獲階段,目標(biāo)階段,事件冒泡階段。返回其事件監(jiān)聽(tīng)器觸發(fā)該事件的元素。清理事務(wù)設(shè)置檢查點(diǎn)的標(biāo)志為。 前端最基礎(chǔ)的就是 HTML+CSS+Javascript。掌握了這三門技術(shù)就算入門,但也僅僅是入門,現(xiàn)在前端開(kāi)發(fā)的定義已經(jīng)遠(yuǎn)遠(yuǎn)不止這些。前端小課堂(HTML/C...
摘要:前端最基礎(chǔ)的就是。幫助從舊的事件方法轉(zhuǎn)換,和。方法移除用綁定的事件處理程序。特定的事件處理程序可以被移除元素上提供事件名稱,命名空間,處理函數(shù)。用于過(guò)濾器的觸發(fā)事件的選擇器元素的后代。事件觸發(fā)模擬觸發(fā)原生使用觸發(fā)。 前端最基礎(chǔ)的就是 HTML+CSS+Javascript。掌握了這三門技術(shù)就算入門,但也僅僅是入門,現(xiàn)在前端開(kāi)發(fā)的定義已經(jīng)遠(yuǎn)遠(yuǎn)不止這些。前端小課堂(HTML/CSS/JS)...
摘要:前端最基礎(chǔ)的就是。幫助從舊的事件方法轉(zhuǎn)換,和。方法移除用綁定的事件處理程序。特定的事件處理程序可以被移除元素上提供事件名稱,命名空間,處理函數(shù)。用于過(guò)濾器的觸發(fā)事件的選擇器元素的后代。事件觸發(fā)模擬觸發(fā)原生使用觸發(fā)。 前端最基礎(chǔ)的就是 HTML+CSS+Javascript。掌握了這三門技術(shù)就算入門,但也僅僅是入門,現(xiàn)在前端開(kāi)發(fā)的定義已經(jīng)遠(yuǎn)遠(yuǎn)不止這些。前端小課堂(HTML/CSS/JS)...
閱讀 2646·2021-11-22 15:24
閱讀 1379·2021-11-17 09:38
閱讀 2755·2021-10-09 09:57
閱讀 1203·2019-08-30 15:44
閱讀 2446·2019-08-30 14:00
閱讀 3547·2019-08-30 11:26
閱讀 2939·2019-08-29 16:28
閱讀 755·2019-08-29 13:56