使用shadow DOM的一個主要好處是樣式隔離。 要了解這意味著什麼,讓我們來假設我們要建立自定義進度條元件。 我們可以使用兩個巢狀的DIV來顯示條形,使用另一個DIV來顯示文字以顯示百分比,如下所示:
<style>
.progress { position: relative; border: solid 1px;width: 100px; height: 1rem; }
.progress > .bar { background: red; height: 100%; }
.progress > .label {
position: absolute; top: 0;
width: 100%;
text-align: center; font-size: 0.8rem;}
</style>
<template id="progress-bar-template">
<div class="progress">
<div class="bar"></div>
<div class="label">0%</div>
</div>
</template>
<script>
function createProgressBar() {
var fragment = document.getElementById(`progress-bar-template`).content.cloneNode(true);
var progressBar = fragment.querySelector(`div`);
progressBar.updateProgress = function (newPercentage) {
var ps = newPercentage + `%`
this.querySelector(`.label`).textContent = ps
this.querySelector(`.bar`).style.width = ps
}
return progressBar;
}
var p = createProgressBar()
document.body.appendChild(p)
p.updateProgress(22)
</script>
請注意模板元素的使用:
- 它允許作者包含HTML片段,以後可以通過克隆內容來例項化
- 模板元素可以出現在文件中的任何位置(例如,在表格和tr元素之間)
- 模板元素中的內容是惰性的,不執行指令碼或載入影像和其他型別的子資源。
這個進度條實現的問題是它的兩個內部div可以被使用者自由訪問,它的樣式規則也不侷限於進度條。 例如,為進度條定義的樣式規則將應用於進度條外部的內容,其類名為progress:
<section class="project">
<p class="progress">Pending an approval</p>
</section>
同樣的,為其他元素定義的樣式規則可以覆蓋進度條中的規則:
<style>
.label { font-weight: bold; }
</style>
雖然我們可以通過使用自定義元素名稱(如custom-progressbar)來規範規則,然後通過以下方式初始化所有其他屬性來解決這些問題
all: initial
但Shadow DOM提供了更優雅的解決方案,外部div處引入封裝層,以便進度條元件的使用者看不到其內部實現(例如為標籤和條建立的div)。還有為進度條定義的CSS樣式不會干擾頁面的其餘部分,反之亦然。 為此,我們首先通過呼叫在進度條上建立一個ShadowRoot:
attachShadow({mode: `closed`})
然後在其下附加其實現所需的各種DOM實現。 假設我們仍然使用div來掛接這個Shadow Root,如下所示:
<body>
<template id="progress-bar-template">
<div class="progress">
<div class="bar"></div>
<div class="label">0%</div>
</div>
<style>
.progress { position: relative; border: solid 1px;width: 100px; height: 1rem; }
.progress > .bar { background: red; height: 100%; }
.progress > .label {
position: absolute; top: 0;
width: 100%;
text-align: center; font-size: 0.8rem;}
</style>
</template>
<script>
function createProgressBar() {
var progressBar = document.createElement(`div`);
var shadowRoot = progressBar.attachShadow({mode: `closed`});
shadowRoot.appendChild(document.getElementById(`progress-bar-template`).content.cloneNode(true));
progressBar.updateProgress = function (newPercentage) {
shadowRoot.querySelector(`.label`).textContent = newPercentage + `%`;
shadowRoot.querySelector(`.bar`).style.width = newPercentage + `%`;
}
return progressBar;
}
var p = createProgressBar()
document.body.appendChild(p)
p.updateProgress(22)
</script></body>
請注意,style元素位於模板元素內部,並與div一起克隆到Shadow Root內。這允許在陰影根中定義的樣式規則作用域。 在陰影根之外定義的樣式規則就無法適用於Shadow Root內的元素。
使用開啟模式,您可以通過HTML元素的shadowRoot屬性訪問Shadow DOM。關閉模式你不能。 shadowRoot將返回null。封閉模式的設計目標是禁止對來自外部世界的Shadow Root中的節點進行任何訪問。