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