Shadow DOM的了解
Shadow DOM
是
HTML
的一個規範,其允許在文檔
document
渲染時插入一顆
DOM
元素子樹,但是這棵子樹不在主
DOM
樹中,
Shadow DOM
如果按照英文翻譯的話可以翻譯為影子
DOM
,是一種不屬于主
DOM
樹的獨立的結構。
描述
Web components
的一個重要屬性是封裝——可以将标記結構、樣式和行為隐藏起來,并與頁面上的其他代碼相隔離,保證不同的部分不會混在一起,可使代碼更加幹淨、整潔,在這裡
Shadow DOM
接口是關鍵所在,它可以将一個隐藏的、獨立的
DOM
附加到一個元素上,
Shadow DOM
标準允許你為你自己的元素
custom element
維護一組
Shadow DOM
。
Shadow DOM
允許将隐藏的
DOM
樹附加到正常的
DOM
樹中,它以
shadow root
節點為起始根節點,在這個根節點的下方,可以是任意元素,和普通的
DOM
元素一樣,另外還有一些
Shadow DOM
特有的術語。
-
: 一個正常Shadow host
節點,DOM
會被附加到這個節點上。Shadow DOM
-
:Shadow tree
内部的Shadow DOM
樹。DOM
-
Shadow boundary
結束的地方,也是正常Shadow DOM
開始的地方。DOM
-
Shadow root
的根節點。Shadow tree
我們可以使用同樣的方式來操作
Shadow DOM
,就和操作正常
DOM
一樣——例如添加子節點、設定屬性,以及為節點添加自己的樣式(例如通過
element.style
屬性),或者為整個
Shadow DOM
添加樣式(例如在
<style>
元素内添加樣式),不同的是
Shadow DOM
内部的元素始終不會影響到它外部的元素(除了
:focus-within
),這就為封裝提供了便利。
此外不管從哪個方面來看
Shadow DOM
都不是一個新事物,在過去的很長一段時間裡,浏覽器用它來封裝一些元素的内部結構,以一個有着預設播放控制按鈕的
<video>
元素為例,我們所能看到的隻是一個
<video>
标簽,實際上,在它的
Shadow DOM
中,包含來一系列的按鈕和其他控制器。再舉一個例子我們都知道像
React
或
Vue
這樣的都有元件的概念,我們常用的
<input>
、
<audio>
<video>
等這些元素,其實它也是以元件的形式存在的,即
HTML Web Component
這些都有自己的
Shadow DOM
,這些元件内部是由自身的一些
HTML
标簽組成的。
現代浏覽器
Firefox
Chrome
Opera
和
Safari
等預設支援
Shadow DOM
,基于
Chromium
的新
Edge
也支援
Shadow DOM
,而舊
Edge
未能撐到支援此特性,至于
IE
浏覽器嘛
...
,相容性方面可以查閱此處
https://caniuse.com/?search=Shadow%20DOM
示例
<!DOCTYPE html>
<html>
<head>
<title>Shadow DOM</title>
<style>
.text{
color: blue; /* 設定字型顔色 */ /* 可以看出在外部定義的樣式無法影響到影子内部元素樣式 */
}
</style>
</head>
<body>
<div id="app">
<div class="shadow-cls"></div>
</div>
</body>
<script type="text/javascript">
(function(doc, win){
var shadowHost = doc.querySelector(".shadow-cls"); // 擷取影子宿主shadow host
var shadowRoot = shadowHost.attachShadow({mode: "open"}); // 建立(附加)影子shadow root // open 表示可以通過頁面内的 JavaScript 方法來擷取 Shadow DOM
var style = doc.createElement("style"); // 建立style元素
style.textContent = `
.text{
font-style: italic;
}
`; // 影子内部樣式
const template = `
<div>
<div class="text">Text</div>
</div>
`; // 模闆 // 另外可以嘗試 <template> 以及 <script text/template>
const container = doc.createElement("div"); // 建立容器
container.innerHTML = template; // 加入容器
shadowRoot.append(style, container); // 加入影子
})(document, window);
</script>
</html>
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://segmentfault.com/a/1190000017970486
https://www.cnblogs.com/tugenhua0707/p/10545179.html
https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_shadow_DOM