成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

瀏覽器內(nèi)核之 HTML 解釋器和 DOM 模型

Carbs / 1286人閱讀

摘要:書(shū)接上文瀏覽器內(nèi)核之資源加載與網(wǎng)絡(luò)棧本文介紹的模型之后,深入的核心部分,剖析的解釋器是如何將從網(wǎng)絡(luò)或者本地文件獲取的字節(jié)流轉(zhuǎn)成內(nèi)部表示的結(jié)構(gòu)樹(shù)。事件處理最重要就是事件捕獲和事件冒泡這兩種機(jī)制。

微信公眾號(hào):愛(ài)寫(xiě)bugger的阿拉斯加
如有問(wèn)題或建議,請(qǐng)后臺(tái)留言,我會(huì)盡力解決你的問(wèn)題。
前言

此文章是我最近在看的【W(wǎng)ebKit 技術(shù)內(nèi)幕】一書(shū)的一些理解和做的筆記。
而【W(wǎng)ebKit 技術(shù)內(nèi)幕】是基于 WebKit 的 Chromium 項(xiàng)目的講解。

書(shū)接上文 瀏覽器內(nèi)核之資源加載與網(wǎng)絡(luò)棧

本文介紹 W3C 的 DOM 模型之后,深入 WebKit 的核心部分,剖析 WebKit 的 HTML 解釋器是如何將從網(wǎng)絡(luò)或者本地文件獲取的字節(jié)流轉(zhuǎn)成內(nèi)部表示的結(jié)構(gòu) --- DOM 樹(shù)。

1. DOM 模型 1.1.1 DOM 標(biāo)準(zhǔn)

DOM (Document Object Model)的全稱是文檔對(duì)象模型,它可以以一種獨(dú)立于平臺(tái)和語(yǔ)言的方式訪問(wèn)和修改一個(gè)文檔的內(nèi)容和結(jié)構(gòu)。這里的文檔可以是 HTML 文檔、XML 文檔或者 XHTML 文檔。DOM 以面向?qū)ο蟮姆绞絹?lái)描述文檔,在 HTML 文檔中,Web 開(kāi)發(fā)者可以使用 JavaScript 語(yǔ)言來(lái)訪問(wèn)、創(chuàng)建、刪除或者修改 DOM 結(jié)構(gòu),其主要目的是動(dòng)態(tài)改變 HTML 文檔的結(jié)構(gòu)。

使用 DOM 表示的文檔被描述成一個(gè)樹(shù)形結(jié)構(gòu),使用 DOM 的接口可以對(duì) DOM 樹(shù)結(jié)構(gòu)進(jìn)行操作。

每一級(jí)的版本都對(duì)以前的版本進(jìn)行了補(bǔ)充并伴隨新功能的加入,每個(gè)版本都對(duì) DOM 的不同部分進(jìn)行了定義。

1.1.2 DOM 樹(shù) 1.1.2.1 結(jié)構(gòu)模型

DOM 結(jié)構(gòu)構(gòu)成的基本要素是 “節(jié)點(diǎn)” ,而文檔的 DOM 結(jié)構(gòu)就是由層次化的節(jié)點(diǎn)組成。在 DOM 模型中,節(jié)點(diǎn)的概念很寬泛,整個(gè)文檔(Document )就是一個(gè)節(jié)點(diǎn),稱為文檔節(jié)點(diǎn)。HTML 中的標(biāo)記(Tag)也是一種節(jié)點(diǎn),稱為元素(Element)節(jié)點(diǎn)。還有一些其他類型的節(jié)點(diǎn),例如 屬性節(jié)點(diǎn)(標(biāo)記的屬性)、Entity 節(jié)點(diǎn)、ProcessingIntruction 節(jié)點(diǎn)、CDataSection 節(jié)點(diǎn)、注釋(Comment)節(jié)點(diǎn)等。

1.1.2.2 DOM 樹(shù)

眾多的節(jié)點(diǎn)按照層次組織構(gòu)成一個(gè) DOM 樹(shù)結(jié)構(gòu)。
如圖 5 - 4

DOM 樹(shù)的根就是 HTMLDocument , HTML 網(wǎng)頁(yè)中的標(biāo)簽則被轉(zhuǎn)換成一個(gè)個(gè)的元素節(jié)點(diǎn)。同數(shù)據(jù)結(jié)構(gòu)中的樹(shù)形結(jié)構(gòu)一樣,這些節(jié)點(diǎn)之間也存在父子或兄弟關(guān)系。

1.2 HTML 解釋器 1.2.1 解釋過(guò)程

HTML 解釋器的工作就是將網(wǎng)絡(luò)或者本地磁盤(pán)獲取的 HTML 網(wǎng)頁(yè)和資源從字節(jié)流解釋成 DOM 樹(shù)結(jié)構(gòu)。這一過(guò)程大致可以理解成圖 5-5所述的步驟。

這過(guò)程中,WebKit 內(nèi)部對(duì)網(wǎng)頁(yè)內(nèi)容在各個(gè)階段的結(jié)構(gòu)表示。 WebKit 中這一過(guò)程如下:首先是字節(jié)流,經(jīng)過(guò)解碼之后是字符流,然后通過(guò)詞法分析器會(huì)被解釋成詞語(yǔ)(Tokens),之后經(jīng)過(guò)語(yǔ)法分析器構(gòu)建成節(jié)點(diǎn),最后這些節(jié)點(diǎn)被組建成一棵 DOM 樹(shù)。

1.2.2 詞法分析

在進(jìn)行詞法分析之前,解釋器首先要做的事情就是檢查該網(wǎng)頁(yè)內(nèi)容使用的編碼格式,以便后面使用合適的解碼器。如果解釋器在 HTML 網(wǎng)頁(yè)中找到了設(shè)置的編碼格式, WebKit 會(huì)使用相應(yīng)的解碼器來(lái)將字節(jié)流轉(zhuǎn)換成特定格式的字符串。如果沒(méi)有特殊格式,詞法分析器 HTMLTokenizer 類可以直接進(jìn)行詞法分析。

詞法分析的工作都是由 HTMLTokenizer 來(lái)完成 ,簡(jiǎn)單來(lái)說(shuō),它就是一個(gè)狀態(tài)機(jī)---輸入的是字符串,輸出的是一個(gè)個(gè)詞語(yǔ)。因?yàn)樽止?jié)流可能是分段的,所以輸入的字符串可能也是分段的,但是這對(duì)詞法分析器來(lái)說(shuō)沒(méi)有什么特別之處,它會(huì)自己維護(hù)內(nèi)部的狀態(tài)信息。

詞法分析器的主要接口是 “nextToken” 函數(shù),調(diào)用者只需要關(guān)鍵字符串傳入,然后就會(huì)得到一個(gè)詞語(yǔ),并對(duì)傳入的字符串設(shè)置相應(yīng)的信息,表示當(dāng)前處理完的位置,如此循環(huán),如果詞法分析器遇到錯(cuò)誤,則報(bào)告狀態(tài)錯(cuò)誤碼,主要邏輯在圖 5-8 中給予了描述。

對(duì)于 “nextToken” 函數(shù)的調(diào)用者而言,它首先設(shè)置輸入需要解釋的字符串,然后循環(huán)調(diào)用 NextToken 函數(shù),直到處理結(jié)束。 “nextToken” 方法每次輸出一個(gè)詞語(yǔ),同時(shí)會(huì)標(biāo)記輸入的字符串,表明哪些字符已經(jīng)被處理過(guò)了。因此,每次詞法分析器都會(huì)根據(jù)上次設(shè)置的內(nèi)部狀態(tài)和上次處理之后的字符串來(lái)生成一個(gè)新的詞語(yǔ)。 “nextToken” 函數(shù)內(nèi)部使用了超過(guò) 70 種狀態(tài),圖中只顯示了 3 種狀態(tài)。對(duì)于每個(gè)不同的狀態(tài),都有相應(yīng)的處理邏輯。

1.2.3 XSSAuditor 驗(yàn)證詞語(yǔ)

當(dāng)詞語(yǔ)生成之后,WebKit 需要使用 XSSAuditor 來(lái)驗(yàn)證詞語(yǔ)流(Token Stream)。XSS 指的是 Cross Site Security , 主要是針對(duì)安全方面的考慮。

根據(jù) XSS 的安全機(jī)制,對(duì)于解析出來(lái)的這些詞語(yǔ),可能會(huì)阻礙某些內(nèi)容的進(jìn)一步執(zhí)行,所以 XSSAuditor 類主要負(fù)責(zé)過(guò)濾這些被阻止的內(nèi)容,只有通過(guò)的詞語(yǔ)才會(huì)作后面的處理。

1.2.4 詞語(yǔ)到節(jié)點(diǎn)

經(jīng)過(guò)詞法分析器解釋之后的詞語(yǔ)隨之被 XSSAuditor 過(guò)濾并且在沒(méi)有被阻止之后,將被 WebKit 用來(lái)構(gòu)建 DOM 節(jié)點(diǎn)。從詞語(yǔ)到構(gòu)建節(jié)點(diǎn)的步驟是由 HTMLDocumentParser 類調(diào)用 HTMLTreeBuilder 類的 “constructTree” 函數(shù)來(lái)實(shí)現(xiàn)。

1.2.5 節(jié)點(diǎn)到 DOM 樹(shù)

從節(jié)點(diǎn)到構(gòu)建 DOM 樹(shù),包括為樹(shù)中的元素節(jié)點(diǎn)創(chuàng)建屬性節(jié)點(diǎn)等工作由 HTMLConstructionSite 類來(lái)完成。正如前面介紹的,該類包含一個(gè) DOM 樹(shù)的根節(jié)點(diǎn) ——HTMLDocument 對(duì)象,其他的元素節(jié)點(diǎn)都是它的后代。

因?yàn)?HTML 文檔的 Tag 標(biāo)簽是有開(kāi)始和結(jié)束標(biāo)記的,所以構(gòu)建這一過(guò)程可以使用棧結(jié)構(gòu)來(lái)幫忙。HTMLConstructionSite 類中包含一個(gè) “HTMLElementStack” 變量,它是一個(gè)保存元素節(jié)點(diǎn)的棧,其中的元素節(jié)點(diǎn)是當(dāng)前有開(kāi)始標(biāo)記但是還沒(méi)有結(jié)束標(biāo)記的元素節(jié)點(diǎn)。想象一下 HTML 文檔的特點(diǎn),例如一個(gè)片段 “

”,當(dāng)解釋到 img 元素的開(kāi)始標(biāo)記時(shí),棧中的元素就是 body 、div 和 img ,當(dāng)遇到 img 的結(jié)束標(biāo)記時(shí),img 退棧, img 是 div 元素的子女;當(dāng)遇到 div 的結(jié)束標(biāo)記時(shí),div 退棧,表明 div 和它的子女都已處理完,以此類推。

同 DOM 標(biāo)準(zhǔn)一樣,一切的基礎(chǔ)都是 Node 類。在 WebKit 中, DOM 中的接口 Interface 對(duì)應(yīng)于 C++ 的類,Node 類是其他類的基類,圖 5-10 顯示了 DOM 的主要相關(guān)節(jié)點(diǎn)類。圖中的 Node 類實(shí)際上繼承自 EventTarget 類,它表明 Node 類能夠接受事件,這個(gè)會(huì)在 DOM 事件處理中介紹。Node 類還繼承自另外一個(gè)基類 ——ScriptWrappable,這個(gè)跟 JavaScript 引擎相關(guān)。

Node 的子類就是 DOM 中定義的同名接口,元素類,文檔類和屬性類均繼承自一個(gè)抽象出來(lái)的 ContainerNode 類,表明它們能夠包含其他的節(jié)點(diǎn)對(duì)象。回到 HTML 文檔來(lái)說(shuō),元素和文檔對(duì)應(yīng)的類注是 HTMLElement 類和 HTMLDocument 類,實(shí)際上 HTML 規(guī)范還包含眾多的 HTMLElement 子類,用于表示 HTML 語(yǔ)法中眾多的標(biāo)簽。

1.2.6 網(wǎng)頁(yè)基礎(chǔ)設(shè)施

上面介紹了 Frame 、Document 等 WebKit 中的基礎(chǔ)類,這些都是網(wǎng)頁(yè)內(nèi)部的概念,實(shí)際上,WebKit 提供了更高層次的設(shè)施,用于表示整個(gè)網(wǎng)頁(yè)的一些類,WebKit 中的 接口部分 就是基于它們來(lái)提供的,表示網(wǎng)頁(yè)的類既提供了構(gòu)建 DOM 樹(shù)等操作,同時(shí)也提供了接口用于布局。渲染等操作。

1.2.7 線程化的解釋器

在 Renderer 進(jìn)程中有一個(gè)線程,該線程用來(lái)處理 HTML 文檔的解釋任務(wù),在 HTML 解釋器的步驟中,WebKit 的 Chromium 移植跟其他的 WebKit 移植也存在不同之處。

線程化的解釋器就是利用多帶帶的線程來(lái)解釋 HTML 文檔。因?yàn)樵赪ebKit 中,網(wǎng)絡(luò)資源的字節(jié)流自 IO 線程傳遞給渲染線程之后,后面的解釋、布局和渲染等工作基本上就是工作在該線程,也就是渲染線程完成的(這不是絕對(duì)的)。因?yàn)?DOM 樹(shù)只能在渲染線程上創(chuàng)建和訪問(wèn),這也就是說(shuō)構(gòu)建 DOM 樹(shù)的過(guò)程只能在渲染線程中進(jìn)行。但是,從字符到詞語(yǔ)這個(gè)階段可以交給多帶帶的線程來(lái)做,Chromium 瀏覽器使用的就是這個(gè)思想。

具體的實(shí)現(xiàn)過(guò)程:

字符串 (傳給)=> HTMLDocumentParser類 (創(chuàng)建一個(gè)新的對(duì)象)=> BackgroundHTMLParser 來(lái)負(fù)責(zé)處理 (交給)=> 前一步創(chuàng)建的對(duì)象

WebKit 會(huì)檢查是否需要?jiǎng)?chuàng)建用于解釋字符串的線程 HTMLParserThread 。如果該線程已存在,WebKit 就將剛剛的任務(wù)傳遞給這一新線程, 圖 5-13 描述了這一過(guò)程。

在 HTMLParserThread 線程中,WebKit 所做的事情包括將字符串解釋成一個(gè)個(gè)詞語(yǔ),然后使用之前提到的 XSSAuditor 進(jìn)行安全檢查。這是在一個(gè)新的線程中執(zhí)行。主要區(qū)別在于解釋成詞語(yǔ)之后,WebKit 會(huì)分批次地將結(jié)果詞語(yǔ)傳遞給渲染線程。

1.2.8 JavaScript 的執(zhí)行

在 HTML 解釋器的工作過(guò)程中,可能會(huì)有 JavaScript 代碼(全局作用域的代碼)需要執(zhí)行,它發(fā)生在將字符串解釋成詞語(yǔ)之后、創(chuàng)建各種節(jié)點(diǎn)的時(shí)候。這也是全局執(zhí)行的 JavaScript 代碼不能訪問(wèn) DOM 樹(shù)的原因——因?yàn)?DOM 樹(shù)還沒(méi)有被創(chuàng)建完。

所以建議 JavaScript 的使用如下:

1、將 “script” 元素加上 “async” 屬性,表明這是一個(gè)可以異步執(zhí)行的 JavaScript 代碼。

2、將 “script” 元素放在 “body” 元素的最后,這樣它不會(huì)阻礙其他資源的并發(fā)下載。

但是不這樣做的時(shí)候,WebKit 使用預(yù)掃描和預(yù)加載機(jī)制來(lái)實(shí)現(xiàn)資源的并發(fā)下載而不被 JavaScript 的執(zhí)行所阻礙。

具體做法是:當(dāng)遇到需要執(zhí)行 JavaScript 代碼的時(shí)候,WebKit 先暫停當(dāng)前 JavaScript 代碼的執(zhí)行,使用預(yù)先掃描器 HTMLPreloadScanner 類來(lái)掃描后面的詞語(yǔ)。如果 WebKit 發(fā)現(xiàn)它們需要使用其他資源,那么使用預(yù)資源加載器 HTMLPreloadScanner 類來(lái)發(fā)送請(qǐng)求,在這之后,才執(zhí)行 JavaScript代碼。預(yù)先掃描器本身并不創(chuàng)建節(jié)點(diǎn)對(duì)象,也不會(huì)構(gòu)建 DOM 樹(shù),所以速度比較快。

當(dāng) DOM 樹(shù)構(gòu)建完之后,WebKit 觸發(fā) “DOMContentLoaded” 事件,注冊(cè)在該事件上的 JavaScript 函數(shù)會(huì)被調(diào)用。當(dāng)所在資源都被加載完之后,WebKit 觸發(fā) “onload” 事件。

WebKit 將 DOM 樹(shù)創(chuàng)建過(guò)程中需要執(zhí)行的 JavaScript 代碼交由 HTMLScriptRunner 類來(lái)負(fù)責(zé)。工作方式很簡(jiǎn)單,就是利用 JavaScript 引擎來(lái)執(zhí)行 Node 節(jié)點(diǎn)中包含的代碼,具體可以參考 “HTMLScriptRunner::executeParsingBlockingScript” 方法。

1.3 DOM 事件機(jī)制 1.3.1 事件的工作過(guò)程

事件在工作過(guò)程中使用兩個(gè)主體,第一個(gè)是事件(event),第二個(gè)是事件目標(biāo)(EventTarget)。WebKit 中用 EventTarget 類來(lái)表示 DOM 規(guī)范中 Events 部分定義的事件目標(biāo)。

每個(gè) 事件都有屬性來(lái)標(biāo)記該事件的事件目標(biāo)。當(dāng)事件到達(dá)事件目標(biāo)(如一個(gè)元素節(jié)點(diǎn))的時(shí)候,在這個(gè)目標(biāo)上注冊(cè)的監(jiān)聽(tīng)者(Event Listeners)都會(huì)有觸發(fā)調(diào)用,而這些監(jiān)聽(tīng)者的調(diào)用順序不是固定的,所以不能依賴監(jiān)聽(tīng)者注冊(cè)的順序來(lái)決定你的代碼邏輯。

圖 5-17 是 EventTarget 接口的定義。圖中的接口是用來(lái)注冊(cè)和移除監(jiān)聽(tīng)者的。

事件處理最重要就是事件捕獲(Event capture)和事件冒泡(Event bubbling)這兩種機(jī)制。圖 5-18 是事件捕獲和事件冒泡的過(guò)程。

當(dāng)渲染引擎接收到一個(gè)事件的時(shí)候,它會(huì)通過(guò) HitTest(WebKit 中的一種檢查觸發(fā)gkwrd哪個(gè)區(qū)域的算法)檢查哪個(gè)元素是直接的事件目標(biāo)。在圖 5-18 中,以 “img” 為例,假設(shè)它是事件的直接目標(biāo),這樣,事件會(huì)經(jīng)過(guò)自頂向下和自底向上的兩個(gè)過(guò)程。

事件的捕獲是自頂向下,事件先是到 document 節(jié)點(diǎn),然后一路到達(dá)目標(biāo)節(jié)點(diǎn)。在圖 5-18 中,順序就是 “#document” -> "HTML" -> "body" -> "img" 這樣一個(gè)順序。事件可以在這一傳遞過(guò)程中被捕獲,只需要在注冊(cè)監(jiān)聽(tīng)者的時(shí)候設(shè)置相應(yīng)參數(shù)即可。默認(rèn)情況下,其他節(jié)點(diǎn)不捕獲這樣的事件。如果網(wǎng)頁(yè)注冊(cè)了這樣的監(jiān)聽(tīng)者,那么監(jiān)聽(tīng)者的回調(diào)函數(shù)會(huì)被調(diào)用,函數(shù)可以通過(guò)事件的 “stopPropagation” 函數(shù)來(lái)阻止事件向下傳遞。

事件的冒泡過(guò)程是從下向上的順序,它的默認(rèn)行為是不冒泡,但是是事件包含一個(gè)是否冒泡的屬性。當(dāng)這一屬性為真的時(shí)候,渲染引擎會(huì)將該事件首先傳遞給事件的目標(biāo)節(jié)點(diǎn)的父親,然后是父親的父親,以此類推。同捕獲動(dòng)作一樣,這此監(jiān)聽(tīng)函數(shù)也可以使用 “stopPropagation” 函數(shù)來(lái)阻止事件向上傳遞。

1.3.2 WebKit 的事件處理機(jī)制

DOM 的事件分為很多種,與用戶相關(guān)的只是其中的一種,稱為 UIEvent ,其他的包括 CustomEvent、MutationEvent 等。UIEvent 又可以分為很多種,包括但是不限于 FocusEvent、MouseEvent、KeyboardEvent、Composition 等。

基于 WebKit 的瀏覽器事件處理過(guò)程,首先是做 HitTest ,查找事件發(fā)生處的元素,檢查該元素有無(wú)監(jiān)聽(tīng)者。如果網(wǎng)頁(yè)的相關(guān)節(jié)點(diǎn)注冊(cè)了事件的監(jiān)聽(tīng)者,那么瀏覽器會(huì)把事件派發(fā)給 WebKit 內(nèi)核來(lái)處理。同時(shí),瀏覽器也可能需要理解和處理這樣的事件。這主要是因?yàn)?,有些事件瀏覽器必須響應(yīng)從而對(duì)網(wǎng)頁(yè)作默認(rèn)處理。

EventHandler 類是處理事件的核心類,它除了需要將各種事件傳給 JavaScript 引擎以調(diào)用響應(yīng)的監(jiān)聽(tīng)者之外,它還會(huì)識(shí)別鼠標(biāo)事件,來(lái)觸發(fā)調(diào)用右鍵菜單、拖放效果等與事件密切相關(guān)的工作,而且 EventHandler 類還支持網(wǎng)頁(yè)的多框結(jié)構(gòu)。EventHandler 類的接口比較容易理解,但是它的處理邏輯極其復(fù)雜。

圖 5-20 簡(jiǎn)單描述了鼠標(biāo)事件的調(diào)用過(guò)程,這一過(guò)程本身是比較簡(jiǎn)單的,復(fù)雜之處在于 WebKit 的 EventHandler 類。

WebKit 中還有些跟事件處理相關(guān)的其他類,例如 EventPathWalker、EventDispatcher 類等,這些類都是為了解決事件在 DOM 樹(shù)中傳遞的問(wèn)題。

1.4 影子(Shadow)DOM

影子 DOM 是一個(gè)新東西,主要解決了一個(gè)文檔中可能需要大量交互的多個(gè) DOM 樹(shù)建立和維護(hù)各自的功能邊界的問(wèn)題。

1.4.1 什么是影子 DOM

當(dāng)開(kāi)發(fā)這樣一個(gè)用戶界面的控件——這個(gè)控件可能由一些 HTML 的標(biāo)簽元素組成,這些元素可以組成一顆 DOM 樹(shù)的子樹(shù)。這樣一個(gè) HTML 控件可以被到處使用,但是問(wèn)題隨之而來(lái),那就是每個(gè)使用控件的地方都會(huì)知道這個(gè)子樹(shù)的結(jié)構(gòu)。

當(dāng)網(wǎng)頁(yè)的開(kāi)發(fā)者需要訪問(wèn)網(wǎng)頁(yè) DOM 樹(shù)的時(shí)候,這些控件內(nèi)部的 DOM 子樹(shù)都會(huì)暴露出來(lái),這些暴露的節(jié)點(diǎn)不僅可能給 DOM 樹(shù)的遍歷帶來(lái)很多麻煩,而且也可能給 CSS 的樣式選擇帶來(lái)問(wèn)題,因?yàn)檫x擇器無(wú)意中可能會(huì)改變這些內(nèi)部節(jié)點(diǎn)的樣式,從而導(dǎo)致很奇怪的控件界面。

如何將內(nèi)部的節(jié)點(diǎn)信息封裝起來(lái),就像 C++ 語(yǔ)言的類一樣,同時(shí)又能夠?qū)⑦@些節(jié)點(diǎn)渲染出來(lái)呢 ? W3C 工作組提出的影子 DOM 概念。影子 DOM 的規(guī)范草案能夠使得一些 DOM 節(jié)點(diǎn)在特定范圍內(nèi)可見(jiàn),而在網(wǎng)頁(yè)的 DOM 樹(shù)中卻不可見(jiàn),但是網(wǎng)頁(yè)渲染的結(jié)果中包含了這些節(jié)點(diǎn),這就使得封裝變得容易很多。

圖 5-21 描述了 HTML 文檔對(duì)應(yīng)的 DOM 樹(shù)和 “div” 元素包含的一個(gè)影子 DOM 子樹(shù)。當(dāng)使用 JavaScript 代碼訪問(wèn) HTML 文檔的 DOM 樹(shù)的時(shí)候,通常的接口是不能直接訪問(wèn)到影子 DOM 子樹(shù)中的節(jié)點(diǎn)的,JavaScript 代碼只能通過(guò)特殊的接口方式。

HTML5 支持了很多新的特性,例如對(duì)視頻、音頻的支持,讀者會(huì)發(fā)現(xiàn)這些元素其實(shí)是由很復(fù)雜的控制界面組成,這些界面也是使用 HTML 元素編寫(xiě),但是在 DOM 樹(shù)中,你無(wú)法找到相應(yīng)的節(jié)點(diǎn),這其實(shí)也是使用了影子 DOM 的思想。

因?yàn)橛白?DOM 的子樹(shù)在整個(gè)網(wǎng)頁(yè)的 DOM 樹(shù)中不可見(jiàn),那么事件是如何處理的呢 ?事件中需要包含事件目標(biāo),這個(gè)目標(biāo)當(dāng)然不能是不可見(jiàn)的 DOM 節(jié)點(diǎn),所以事件目標(biāo)其實(shí)就是包含影子 DOM 子樹(shù)的節(jié)點(diǎn)對(duì)象。事件捕獲的邏輯沒(méi)有發(fā)生變化,在影子 DOM 子樹(shù)內(nèi)也會(huì)繼續(xù)傳遞。當(dāng)影子 DOM 子樹(shù)中的事件向上冒泡的時(shí)候, WebKit 會(huì)同時(shí)向整個(gè)文檔的 DOM 上傳遞該事件,以避免一些很奇怪的行為。

1.4.2 WebKit 的支持

WebKit 已經(jīng)支持影子 DOM 的規(guī)范草案,雖然還存在一些問(wèn)題。支持影子 DOM 的相關(guān)類在目錄 “Source/core/dom/shadow” 下,里面的主要類是 ShadowRoot ,表示的是影子 DOM 的根節(jié)點(diǎn)。ShadowRoot 類繼承自 DocumentFragment 類,所以它同樣有 Node 節(jié)點(diǎn)的屬性和方法,因而在影子 DOM 樹(shù)的內(nèi)部,遍歷樹(shù)沒(méi)有什么特別不同的地方。

當(dāng)遍歷 HTML 文檔對(duì)應(yīng) DOM 樹(shù)的時(shí)候,WebKit 需要做特別的判斷,所以讀者會(huì)發(fā)現(xiàn)在 WebKit 的 Node 類實(shí)現(xiàn)中存在大量的條件語(yǔ)句,用來(lái)檢查當(dāng)前節(jié)點(diǎn)是否是 ShadowRoot 對(duì)象,如果是該類的對(duì)象,把它作為不同 DOM 樹(shù)之間的邊界。有時(shí)候 WebKit 還需要對(duì) ShadowRoot 對(duì)象作出特別處理,比如某些情況會(huì)略過(guò)它的子樹(shù),同樣的,在事件處理的支持類 EventPathWalker 和 EventRetargeter 中,也需要做一些特別的處理邏輯,原理就是上面所述,細(xì)節(jié)不再介紹。

1.4.3 實(shí)踐:使用影子 DOM

示例代碼 5-2 給出了一個(gè)簡(jiǎn)單的使用 webkitCreateShadowRoot 接口來(lái)創(chuàng)建影子 DOM 子樹(shù)的例子。網(wǎng)頁(yè)只包含了一個(gè) “div” 元素,JavaScript 代碼使用該元素創(chuàng)建了一個(gè)影子 DOM 子樹(shù)的根節(jié)點(diǎn),然后該根節(jié)點(diǎn)下加入了兩個(gè)子女,第一個(gè)是圖片元素,第二個(gè)是 “div” 元素,該元素內(nèi)部包含了一些文本。

讀者可以打開(kāi) Chrom 瀏覽器的開(kāi)發(fā)者工具,然后打開(kāi)控制臺(tái),在其中輸入 “document.firstChild.firstChild.nextElementSibling.firstElementChild.firstElementChild” 后會(huì)發(fā)現(xiàn)結(jié)果是空的,根據(jù)對(duì)應(yīng)關(guān)系 “#document-> html -> head -> body -> div -> null”,雖然網(wǎng)頁(yè)中沒(méi)有 ‘head’ 元素,但是 DOM 樹(shù)仍然會(huì)創(chuàng)建該節(jié)點(diǎn)。同時(shí)讀者會(huì)發(fā)現(xiàn) “div” 元素沒(méi)有子女,影子 DOM 子樹(shù)真的被隱藏起來(lái)了,成為真正的影子。

最后

希望本文對(duì)你有點(diǎn)幫助。

下期分享 第六章 CSS 解釋器和樣式布局 敬請(qǐng)期待。

對(duì) 全棧開(kāi)發(fā) 有興趣的朋友可以掃下方二維碼關(guān)注我的公眾號(hào) —— 愛(ài)寫(xiě)bugger的阿拉斯加

分享 web 開(kāi)發(fā)相關(guān)的技術(shù)文章,熱點(diǎn)資源,全棧程序員的成長(zhǎng)之路。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/54597.html

相關(guān)文章

  • 《Webkit技術(shù)內(nèi)幕》頁(yè)面渲染過(guò)程

    摘要:文章同步到技術(shù)內(nèi)幕之頁(yè)面渲染過(guò)程最近拜讀了傳說(shuō)中的技術(shù)內(nèi)幕一書(shū),有很大收獲,尤其是對(duì)頁(yè)面渲染有了較深的認(rèn)識(shí)。解析語(yǔ)法分析,基于詞法解釋器生成的新標(biāo)記,構(gòu)建成抽象語(yǔ)法樹(shù),解析器嘗試將其與某條語(yǔ)法規(guī)則進(jìn)行匹配。 文章同步到github《Webkit技術(shù)內(nèi)幕》之頁(yè)面渲染過(guò)程 最近拜讀了傳說(shuō)中的《Webkit技術(shù)內(nèi)幕》一書(shū),有很大收獲,尤其是對(duì)頁(yè)面渲染有了較深的認(rèn)識(shí)。由于功力有限,而且書(shū)中設(shè)...

    vvpvvp 評(píng)論0 收藏0
  • 《Webkit技術(shù)內(nèi)幕》頁(yè)面渲染過(guò)程

    摘要:文章同步到技術(shù)內(nèi)幕之頁(yè)面渲染過(guò)程最近拜讀了傳說(shuō)中的技術(shù)內(nèi)幕一書(shū),有很大收獲,尤其是對(duì)頁(yè)面渲染有了較深的認(rèn)識(shí)。解析語(yǔ)法分析,基于詞法解釋器生成的新標(biāo)記,構(gòu)建成抽象語(yǔ)法樹(shù),解析器嘗試將其與某條語(yǔ)法規(guī)則進(jìn)行匹配。 文章同步到github《Webkit技術(shù)內(nèi)幕》之頁(yè)面渲染過(guò)程 最近拜讀了傳說(shuō)中的《Webkit技術(shù)內(nèi)幕》一書(shū),有很大收獲,尤其是對(duì)頁(yè)面渲染有了較深的認(rèn)識(shí)。由于功力有限,而且書(shū)中設(shè)...

    adam1q84 評(píng)論0 收藏0
  • 《Webkit技術(shù)內(nèi)幕》頁(yè)面渲染過(guò)程

    摘要:文章同步到技術(shù)內(nèi)幕之頁(yè)面渲染過(guò)程最近拜讀了傳說(shuō)中的技術(shù)內(nèi)幕一書(shū),有很大收獲,尤其是對(duì)頁(yè)面渲染有了較深的認(rèn)識(shí)。解析語(yǔ)法分析,基于詞法解釋器生成的新標(biāo)記,構(gòu)建成抽象語(yǔ)法樹(shù),解析器嘗試將其與某條語(yǔ)法規(guī)則進(jìn)行匹配。 文章同步到github《Webkit技術(shù)內(nèi)幕》之頁(yè)面渲染過(guò)程 最近拜讀了傳說(shuō)中的《Webkit技術(shù)內(nèi)幕》一書(shū),有很大收獲,尤其是對(duì)頁(yè)面渲染有了較深的認(rèn)識(shí)。由于功力有限,而且書(shū)中設(shè)...

    forsigner 評(píng)論0 收藏0
  • 覽器內(nèi)核 CSS 釋器樣式布局

    摘要:書(shū)接上文瀏覽器內(nèi)核之解釋器和模型本文剖析的解釋器和樣式布局。根據(jù)生成解釋器類。而后將解釋后的信息設(shè)置到元素的屬性的樣式中,然后設(shè)置標(biāo)記表明該元素需要重新計(jì)算樣式,并觸發(fā)重新計(jì)算布局。 showImg(https://segmentfault.com/img/remote/1460000016215814); 微信公眾號(hào):愛(ài)寫(xiě)bugger的阿拉斯加如有問(wèn)題或建議,請(qǐng)后臺(tái)留言,我會(huì)盡力解決...

    _Dreams 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<