接觸到 Web Component 才第一次聽過的名詞,花了一些時間才真正理解用法。
就請各位看下去吧!
影子 DOM(Shadow DOM)允許你將一個 DOM 樹附加到一個元素上,並且使該樹的內部對於在頁面中運行的 JavaScript 和 CSS 是隱藏的。 --MDN
一般的 DOM 就是 HTML 嗎?
其實 HTML 本身沒有太大的用處,但是瀏覽器將靜態的 HTML 解析成資料模型(物件、節點),而這些節點包含了 屬性、方法,讓我們可以透過 JS 來訪問這些節點,進行存取、新增、刪除或更改內容。
而以上提到的內容指的就是一般的 DOM。
Shadow DOM 是附著在某個元素上的 獨立 DOM 樹,是一種解決一般 DOM 中缺少的 樹封裝 方法。
其實在開發過程中我們常常會遇到需要寫 !important 來覆蓋某些衝突的樣式,而使用 Shadow DOM API,可以透過 封裝 DOM 樹 的機制來解決 CSS 和 JavaScript 的衝突問題,裡面的結構與樣式不會影響到外部,也不會受到外部影響。
(圖片中的用語 light DOM 其實就是一般的 DOM,主要用來跟 shadow DOM 做區分)
好處:
壞處:
要建立 Shadow DOM,需要用 Element.attachShadow() 的方法將 shadow root 附加到元素上,而 Element 就是 Shadow host。
Element.attachShadow({ mode: "open" | "closed" })
注意用法:
<video>, <img> ...)已有內建 shadow DOM,不允許再疊加。<table>、<html> ...) 已有內建行為,不可作為 Shadow DOM。自定義元素 與部分安全、結構簡單的元素(div, span, p, section...)。const div = document.createElement('div');
const shadowRoot = header.attachShadow({mode: 'open'}); // 合法的用法
試試看:嘗試將 shadow DOM 附加到不合法的元素將會導致 NotSupportedError 錯誤
document.createElement('input').attachShadow({mode: 'open'}); // 非法的用法
// Uncaught NotSupportedError

若要在 Chrome 中顯示此類元素的 Shadow root,可以在 DevTools 設定,然後在 elements 部分下方選取 Show user agent shadow DOM
參考連結:https://dom.spec.whatwg.org/#shadow-trees
前一篇我們利用基本的 customElements.define 建立了一個自定元件 cat-spinner,
接下來要加入 Shadow DOM,先建立一個 shadowRoot 變數。
class CatSpinner extends HTMLElement {
constructor() {
super();
// 還記得 this 吧?不記得要回去讀一下基礎的 JS 囉!
// 先建立一個 shadowRoot 變數
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
<style>
.spinner {
width: 40px;
height: 40px;
border: 4px solid #ddd;
border-top-color: #333;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
<div class="spinner"></div>
`;
}
}
customElements.define('cat-spinner', CatSpinner);
打開 Dev Tool 看一下:
你會發現,cat-spinner 作為 Shadow host,加入了 Shadow root 在裡面。

open 模式:
element.shadowRoot 屬性獲取 Shadow Root,並且取得內部節點。closed 模式:
null
const element = document.querySelector('cat-spinner');
console.log('open mode', element.shadowRoot) // 會得到 #shadow-root (open)
console.log('closed mode', element.shadowRoot) // 會得到 null
關於 Shadow DOM 的介紹就到這裡啦ヾ(´∀ ˋ)ノ