最近我在作前端面試題總結系列,感興趣的朋友能夠添加關注,歡迎指正、交流。html
爭取每一個知識點可以多總結一些,至少要作到在面試時,針對每一個知識點均可以侃起來,不至於啞火。前端
在上一篇文章【前端 · 面試 】JavaScript 之你不必定會的基礎題(一)中,有同窗產生了這樣一個疑惑:爲何 click 事件的監聽函數中,this.id
和 event.target.id
的輸出值是不同的?git
今天咱們就來扒一扒這其中的原理。面試
有以下的 HTML 文檔結構:編程
<div id="parent"> <div id="child" class="child"> 點我 </div> </div>
第一次執行以下 JavaScript 代碼:瀏覽器
document.getElementById("parent").addEventListener("click", function () { alert(`parent 事件觸發,` + this.id); }); document.getElementById("child").addEventListener("click", function () { alert(`child 事件觸發,` + this.id); });
第二次執行另外一套 JavaScript 代碼:dom
document.getElementById("parent").addEventListener("click", function (e) { alert(`parent 事件觸發,` + e.target.id); }); document.getElementById("child").addEventListener("click", function (e) { alert(`child 事件觸發,` + e.target.id); });
問題以下:函數
點擊 id 爲 child 的 div 後,JavaScript 代碼的執行結果分別是什麼?post
答案是:學習
對於這個答案中的第二次輸出結果,有人生出了疑惑:爲何 parent 事件觸發時,e.target.id
的結果爲 child呢?不該該是 parent 嗎?
首先,咱們知道,HTML 頁面上 DOM 元素的事件執行順序通常有三個階段:
整個過程以下圖:
事件捕獲和事件冒泡
當一個事件發生在具備父元素的元素上(例如,在咱們的例子中是 child 元素)時,現代瀏覽器運行兩個不一樣的階段 - 捕獲階段和冒泡階段。 在捕獲階段:
<html>
,是否在捕獲階段中註冊了一個onclick
事件處理程序,若是是,則運行它。<html>
中單擊元素的下一個祖先元素,並執行相同的操做,而後是單擊元素再下一個祖先元素,依此類推,直到到達實際點擊的元素。在冒泡階段,偏偏相反:
onclick
事件處理程序,若是是,則運行它<html>
元素。這兩個階段以下圖所示:
在現代瀏覽器中,默認狀況下,全部事件處理程序都在冒泡階段進行註冊,這也是爲何只有一個阻止冒泡方法的方法
event.stopPropagation()
,而沒有阻止捕獲的方法,由於徹底不必。
首先,咱們得有一個清晰的認知:事件冒泡或者事件捕獲,都是針對註冊了事件的元素。
關於 this 和 event.target ,總結以下:
event.target
永遠都指向真正觸發了事件流程的元素 ,即處於事件觸階段的元素。event 還有一個屬性 event.srcElement,它是 event.target 的別名,可是是一個非標準屬性,儘可能不在生產環境中使用。
假若有如下代碼:
parent.onclick = function1; child.onclick = function2;
當咱們點擊 child 時,因爲事件默認會在冒泡階段註冊,因此,不只會執行 function2,以後還會執行 function1,這樣的結果可能不是咱們所指望的,咱們更但願它們的點擊事件之間互不影響。
若是要實現這點,只須要在 function2 中添加 event.stopPropagation()
便可。
如今咱們將題目中的 JavaScript 代碼再增長一份:
document.getElementById("parent").addEventListener("click", function (e) { alert(`parent 事件觸發,` + e.target.id); }, false); document.getElementById("child").addEventListener("click", function (e) { alert(`child 事件觸發,` + e.target.id); }, true);
問題1:若是點擊 child 元素,輸出是什麼?
問題2:若是點擊 parent 元素,輸出是什麼?
能夠看到,如今 parent 的點擊事件是冒泡階段執行,child 的點擊事件是在 捕獲階段執行。
針對問題1,因爲 parent 註冊的是冒泡階段執行,因此它的事件是在 child 觸發階段後的冒泡階段執行的,因此答案應該是:先彈出 「child 事件觸發,child」,再彈出「parent 事件觸發,child」。
針對問題二,雖然 child 註冊的是捕獲階段執行事件,可是 parent 事件流程的捕獲根本走不到它,因此答案應該是:只彈出「parent 事件觸發,parent」。
上面咱們分析了這麼多,其實總結起來就下面幾條:
小問題也有大根源,敢於發現,敢於探究!
~
~本文完,感謝閱讀!
~
學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!
你們好,我是〖編程三昧〗的做者 隱逸王,個人公衆號是『編程三昧』,歡迎關注,但願你們多多指教!
你來,懷揣指望,我有墨香相迎! 你歸,不管得失,惟以餘韻相贈!
知識與技能並重,內力和外功兼修,理論和實踐兩手都要抓、兩手都要硬!