使用shadow DOM的一个主要好处是样式隔离。 要了解这意味着什么,让咱们来假设咱们要建立自定义进度条组件。 咱们可使用两个嵌套的DIV来显示条形,使用另外一个DIV来显示文本以显示百分比,以下所示:web
<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>
请注意模板元素的使用:api
这个进度条实现的问题是它的两个内部div能够被用户自由访问,它的样式规则也不局限于进度条。 例如,为进度条定义的样式规则将应用于进度条外部的内容,其类名为progress:app
<section class="project"> <p class="progress">Pending an approval</p> </section>
一样的,为其余元素定义的样式规则能够覆盖进度条中的规则:dom
<style> .label { font-weight: bold; } </style>
虽然咱们能够经过使用自定义元素名称(如custom-progressbar)来规范规则,而后经过如下方式初始化全部其余属性来解决这些问题this
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内的元素。 code
使用打开模式,您能够经过HTML元素的shadowRoot属性访问Shadow DOM。关闭模式你不能。 shadowRoot将返回null。封闭模式的设计目标是禁止对来自外部世界的Shadow Root中的节点进行任何访问。blog