Shadow DOM 是一种 Web 标准,它允许开发者在主文档的 DOM 中嵌入一个隔离的 DOM 子树,这个子树有自己的元素、样式和脚本,而不会影响主文档。Shadow DOM 的主要作用是封装,可以使得组件的内部结构、样式和行为被隐藏和隔离起来,从而使得组件更加模块化和可复用。
Shadow DOM 的用法
创建一个带有 Shadow DOM 的元素
要创建一个 Shadow DOM,你需要选择一个普通的 DOM 元素并为其调用 attachShadow
方法。mode
选项可以设置为 open
或 closed
,表示是否允许外部 JavaScript 访问 Shadow DOM。
// 创建一个新的 div 元素
const shadowHost = document.createElement('div');
// 将这个 div 元素添加到页面中
document.body.appendChild(shadowHost);
// 为这个 div 元素创建一个 Shadow DOM
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
向 Shadow DOM 添加内容
一旦你创建了 Shadow DOM,就可以通过 shadowRoot
添加内容,就像你在普通 DOM 中做的那样。
// 向 Shadow DOM 添加一些 HTML
shadowRoot.innerHTML = `
<style>
p { color: red; }
</style>
<p>Hello from Shadow DOM!</p>
`;
使用 <template>
和 <slot>
你可以使用 <template>
和 <slot>
标签来定义可重用的模板和插槽,这样你就可以将内容投影到 Shadow DOM 中。
<template id="my-template">
<style>
:host { display: block; }
p { color: blue; }
</style>
<p><slot name="message">Default message</slot></p>
</template>
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('my-template');
const templateContent = template.content;
this.attachShadow({mode: 'open'}).appendChild(templateContent.cloneNode(true));
}
});
</script>
然后你可以像这样使用自定义元素:
<my-element>
<span slot="message">Custom message</span>
</my-element>
当前广泛使用的场景
- Web Components: Shadow DOM 是 Web Components 规范的重要部分,允许创建封装好的自定义元素。
- 组件库: 诸如 Polymer、LitElement 和 Stencil 这样的库和框架使用 Shadow DOM 来创建封装的组件。
- 框架和工具: 某些现代前端框架,如 Angular 的元素封装策略也是利用了 Shadow DOM 的特性。
使用注意事项
- 兼容性: 并非所有浏览器都支持 Shadow DOM,尽管现代浏览器都已有较好的支持,但是应该通过特性检测或者 polyfill 来确保兼容性。
- 封装: Shadow DOM 的封装可能会导致样式和脚本不再像在全局 DOM 中那样容易被覆盖或修改,可能需要使用
:host
、::slotted()
伪元素进行样式穿透。 - 选择器: 由于封装,外部 CSS 选择器和 JavaScript
querySelector
方法无法穿透 Shadow DOM 边界。 - 性能: Shadow DOM 的使用可能会带来额外的性能开销,因为它增加了额外的作用域和封装层。
- 工具和调试: 对 Shadow DOM 的调试和工具支持可能不如普通 DOM,特别是在一些旧的开发工具或环境中。
原文链接:https://juejin.cn/post/7343138527418712099 作者:程序员晚天