Webkit底層原理(4)--DOM事件機制和Shadow DOM

一、DOM事件機制

1. 事件的工作過程

事件在工作過程中使用兩個主體,第一個是事件(event),第二個是事件目標(EventTarget)。每個事件都有屬性來標記該事件的事件目標。當事件到達事件目標的時候,在這個目標上註冊的監聽者(EventListeners)都會被觸發調用,當然這些監聽者的調用順序是不固定的,所以不能依賴監聽者註冊的順序來決定你的代碼邏輯。
事件處理最重要的部分就是事件捕獲(Event capture)和事件冒泡(Event bubbling)這兩種機制。如下圖:
在這裏插入圖片描述
當渲染引擎接收到一個事件的時候,它會通過HitTest(Webkit中的一種檢查觸發事件在哪個區域的算法)檢查哪個元素是直接的事件目標。在上圖中,以“img”元素爲例,假設它是事件的直接目標,這樣,事件會經過自頂向下和自底向上兩個過程。

事件的捕獲是自頂向下,這就是說,事件是先到document節點,然後一路到達目標節點。在上圖中的順序就是“#document-->html-->body-->img”。事件可以在這一傳遞過程中被捕獲,只需要在註冊監聽函數的時候設置相應的參數即可。addEventListener的第三個參數就是表示這個含義。默認情況下,其他節點不捕獲這樣的事件。如果網頁註冊了這樣的監聽函數,那麼監聽函數的回調函數會被調用,函數可以通過事件的stopPropagation函數來阻止事件向下傳遞。

事件的冒泡過程是自底向上,它的默認行爲是不冒泡,但是事件包含一個時候冒泡的屬性。當這一屬性爲真的時候,渲染引擎會將該事件首先傳遞給事件目標節點的父親,然後是父親的父親,一次類推。同捕獲動作一樣,這些監聽函數可以使用preventDefault函數來阻止。

2. Webkit的事件處理機制

DOM的事件分爲很多種,與用戶相關的只是其中一種,稱爲UIEvent,其他的包括CustomEvent、MutationEvent等。UIEvent又可以分爲很多種:FocusEvent、MouseEvent、KeyboardEvent、CompositionEvent等。

基於Webkit的瀏覽器事件處理過程,首先是做HitTest,查找事件發生處的元素,檢測該元素有無監聽者。如果網頁的相關節點註冊了事件的監聽者,那麼瀏覽器會把事件派發給Webkit內核來處理。同時,瀏覽器也有可能需要理解和處理這樣的事件。這主要是因爲有些事件瀏覽器必須響應,從而對網頁作默認處理。比如用戶使用鼠標翻滾網頁。假如當前鼠標的位置就在一個元素之上,並且該元素註冊了監聽函數,就會導致競爭衝突,所以我們應該在監聽代碼中調用preventDefault函數來阻止瀏覽器觸發它的默認行爲,也就是不需要滾動整個網頁。

當事件的派發機制遇到網頁的盒模型特別是很多個盒的時候,情況變得比較複雜,這是因爲事件需要在多個盒子和多個DOM樹之間傳遞。當觸控事件(Touch Events)被引入之後,情況更復雜了。

最後再來看看之前提到的事件從瀏覽器到達Webkit內核之後,Webkit內部調用的過程,這一過程比較簡單,主要是EventHandler類。EventHandler類是處理事件的核心類,它除了需要將各種事件傳遞給JavaScript引擎以調用相應的監聽者之外,還會識別鼠標事件來觸發調用右鍵菜單、拖放效果等工作。

二、影子(Shadow)DOM

影子DOM主要解決了一個HTML文檔中可能需要大量交互的多個DOM建立和維護各自功能邊界的問題。影子DOM 爲Web組件中的DOM和CSS提供了封裝,使得這些東西與主文檔的DOM保持分離,也可以在一個Web組件外部使用影子DOM本身。

1. 什麼是Shadow DOM

想象一下網頁的基礎庫開發者想要開發這樣一個用戶界面的控件:

  1. 這個控件可能由一些HTML元素組成,
  2. 這些元素可以組成一顆DOM樹的子樹,
  3. 這個控件可以被到處使用。

問題隨之而來,每個使用控件的地方都會知道這個子樹的結構。當網頁的開發者需要訪問網頁DOM的時候,這些控件內部的DOM子樹就會暴露出來,這些控件內部的節點不僅可能會給DOM的遍歷帶來麻煩,而且也可能因爲無意中被CSS選中而改變樣式。

於是W3C提出了Shadow DOM,它可以使得一些DOM節點在特定的範圍內可見,而在網頁的DOM樹中卻不可見。這使得封裝組件變得容易很多。當使用JavaScript代碼訪問HTML文檔的DOM樹的時候,普通的接口是不能直接訪問到Shadow DOM中的節點的,JavaScript需要特殊的接口才能訪問。具體可以看一下Shadow DOM文檔

HTML5中有很多新特性,例如視頻音頻,我們會發現這些元素都會比較複雜,但是在DOM樹中就只會看見audio和video標籤,這其實就是使用了Shadow DOM的思想。

既然Shadow DOM在整個網頁DOM樹中不可見,那麼事件如何處理呢?事件中需要包含事件目標,這個目標當然不能是不可見的節點,所以事件目標其實就是包含Shadow DOM子樹的節點對象。事件捕獲的邏輯沒有變化,在Shadow DOM子樹內也會繼續傳遞。當Shadow DOM子樹中事件向上冒泡的時候,Webkit會同時向整個文檔的DOM上傳遞該事件,以避免一些奇怪的行爲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章