什麼是Shadow DOM?
什麼是Shadow DOM?
幾周前,我寫了一篇關於 究竟是什麼DOM 的文章。回顧一下,文件物件模型是HTML文件的表示。瀏覽器使用它來確定頁面上要呈現的內容,並通過Javascript程式來修改頁面的內容,結構或樣式。
例如,讓我們採用以下HTML文件:
<!doctype html> <html lang="en"> <head> <title>My first web page</title> </head> <body> <h1>Hello, world!</h1> <p>How are you?</p> </body> </html>
上面的HTML文件將產生以下DOM樹。
-
html
-
head
-
title
- My first web page
-
-
body
-
h1
- Hello, world!
-
p
- How are you?
-
-
在過去幾年中,您可能聽說過“Shadow DOM”和“Virtual DOM”等術語。這些雖然當然與原始DOM有關,但它們指的是截然不同的概念。在本文中,我將詳細介紹Shadow DOM以及它與原始DOM的區別。在以後的文章中,我將對虛擬DOM進行分析。
一切都是 global 的:+1|type_5:!等等,一切都是 global 的:-1|type_5:
HTML文件中的所有元素和樣式以及DOM都位於一個全域性範圍內。頁面上的任何元素都可以通過 document.querySelector()
方法訪問,無論它在文件中的巢狀程度如何或放置在何處。同樣,應用於文件的CSS可以選擇任何元素,無論它在何處。
當我們想要將樣式應用於整個文件時,可以直接使用 *
選擇頁面上的每個元素並將它們的盒模型進行修改。 box-sizing
* { box-sizing: border-box }
另一方面,有些時候元素需要完全封裝,我們不希望它受到全域性樣式的影響。一個很好的例子是第三方小部件,例如Twitter的“關注”按鈕。以下是該小部件的示例:
Follow @ireaderinokun
Twitter follow @ireaderinokun
假設您啟用了Javascript並且檢查了元素,您會注意到該按鈕是一個<iframe>元素,您實際看到的樣式按鈕其實是載入一個小文件。
這是Twitter可以確保其小部件的預期樣式不受文件中的任何CSS影響的唯一方式。儘管有一些方法可以使用級聯來嘗試實現相同的結果,但是沒有其他方法可以提供與<iframe>相同的效果。
建立Shadow DOM是為了允許在Web平臺上本地封裝和元件化,而不必依賴像<iframe>這樣的工具,而這些工具實際上並不是為此目的而製作的。
DOM中的DOM
您可以將shadow DOM視為“DOM中的DOM”。它是自己獨立的DOM樹,具有自己的元素和樣式,與原始DOM完全隔離。
雖然最近才指定供Web作者使用,但使用者代理多年來一直使用shadow DOM來建立和設定複雜元件(如表單元素)。我們來看一下input。要在頁面上建立一個,我們所要做的就是新增以下元素:
<input type="range">
如果我們深入挖掘,我們會看到這個<input>元素實際上是由幾個較小的<div>元素組成,控制著軌道和滑塊本身。
這是使用shadow DOM實現的。暴露給主機HTML的元素記錄了簡單的<input>,但在其下面有與元件相關的元素和樣式,它們不構成DOM全域性範圍的一部分。
shadow DOM如何工作
為了說明shadow DOM的工作原理,讓我們使用shadow DOM而不是<iframe>來重新建立Twitter“follow”按鈕。
首先,我們從shadow host開始。這是我們想要將新影子DOM附加到原始DOM中的常規HTML元素。對於像Follow按鈕這樣的元件,它還可以包含我們希望在頁面上未啟用Javascript或不支援shadow DOM時顯示的回退元素。
<span class="shadow-host"> <a href="https://twitter.com/ireaderinokun"> Follow @ireaderinokun </a> </span>
請注意,我們不僅僅使用 <a>
元素作為影子主機,因為某些元素(主要是互動元素)不能是影子主機。
要將陰影DOM附加到我們的主機,我們使用attachShadow()方法。
const shadowEl = document.querySelector(".shadow-host"); const shadow = shadowEl.attachShadow({mode: 'open'});
這將建立一個空的shadow root作為我們的shadow host的子項。shadow root 是新的shadow DOM的開始,其方式是 <html>
元素是原始DOM的開頭。我們可以通過#shadow-root 在devtools檢查器中看到我們的shadow-root。
雖然常規HTML子項在檢查器中是可見的,但是當shadow root接管時,它們在頁面上不再可見。
接下來,我們要建立內容以形成新的shadow tree。shadow tree就像一個DOM樹,但是對於shadow DOM而不是常規DOM。要建立我們的跟隨按鈕,我們所需要的只是一個新的 <a>
元素,它與我們已有的後備連結幾乎完全相同,但帶有一個圖示。
const link = document.createElement("a"); link.href = shadowEl.querySelector("a").href; link.innerHTML = <span aria-label="Twitter icon"></span> ${shadowEl.querySelector("a").textContent} ;
我們將這個新元素新增到我們的shadow DOM中,就像使用 appendChild()
方法將任何元素作為子元素新增到另一個元素一樣。
shadow.appendChild(link);
在這一點上,這是我們的元素的樣子:
https://p0.ssl.qhimg.com/t012...
最後,我們可以通過建立一個<style>元素並將其附加到陰影根來新增一些樣式。
const styles = document.createElement("style"); styles.textContent = a, span { vertical-align: top; display: inline-block; box-sizing: border-box; } a { height: 20px; padding: 1px 8px 1px 6px; background-color: #1b95e0; color: #fff; border-radius: 3px; font-weight: 500; font-size: 11px; font-family:'Helvetica Neue', Arial, sans-serif; line-height: 18px; text-decoration: none; } a:hover {background-color: #0c7abf; } span { position: relative; top: 2px; width: 14px; height: 14px; margin-right: 3px; background: transparent 0 0 no-repeat; background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2072%2072%22%3E%3Cpath%20fill%3D%22none%22%20d%3D%22M0%200h72v72H0z%22%2F%3E%3Cpath%20class%3D%22icon%22%20fill%3D%22%23fff%22%20d%3D%22M68.812%2015.14c-2.348%201.04-4.87%201.744-7.52%202.06%202.704-1.62%204.78-4.186%205.757-7.243-2.53%201.5-5.33%202.592-8.314%203.176C56.35%2010.59%2052.948%209%2049.182%209c-7.23%200-13.092%205.86-13.092%2013.093%200%201.026.118%202.02.338%202.98C25.543%2024.527%2015.9%2019.318%209.44%2011.396c-1.125%201.936-1.77%204.184-1.77%206.58%200%204.543%202.312%208.552%205.824%2010.9-2.146-.07-4.165-.658-5.93-1.64-.002.056-.002.11-.002.163%200%206.345%204.513%2011.638%2010.504%2012.84-1.1.298-2.256.457-3.45.457-.845%200-1.666-.078-2.464-.23%201.667%205.2%206.5%208.985%2012.23%209.09-4.482%203.51-10.13%205.605-16.26%205.605-1.055%200-2.096-.06-3.122-.184%205.794%203.717%2012.676%205.882%2020.067%205.882%2024.083%200%2037.25-19.95%2037.25-37.25%200-.565-.013-1.133-.038-1.693%202.558-1.847%204.778-4.15%206.532-6.774z%22%2F%3E%3C%2Fsvg%3E); } ; shadow.appendChild(styles);
這是我們的最後一個要素:
DOM與shadow DOM
在某些方面,shadow DOM是DOM的“精簡”版本。與DOM一樣,它是HTML元素的表示,用於確定在頁面上呈現的內容並啟用元素的修改。但與DOM不同,shadow DOM不是基於完整的獨立文件。正如其名稱所示,shadow DOM始終附加到常規DOM中的元素。沒有DOM,shadow DOM就不存在了。