# 翻譯:Shadow DOM隔離釋義

1000copy發表於2019-02-16

使用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>

請注意模板元素的使用:

  1. 它允許作者包含HTML片段,以後可以通過克隆內容來例項化
  2. 模板元素可以出現在文件中的任何位置(例如,在表格和tr元素之間)
  3. 模板元素中的內容是惰性的,不執行指令碼或載入影像和其他型別的子資源。

這個進度條實現的問題是它的兩個內部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中的節點進行任何訪問。

翻譯來自:

Introducing Slot-Based Shadow DOM API | WebKit

相關文章