什么是 shadow DOM

shadow DOM 是 Web Components 的四大组件之一,它可以将一个隐藏的、独立的 DOM 添加到一个元素上,用来创建基于组件的应用。

Shadow DOM 与普通 DOM 相同,但有两点区别:

  1. 创建/使用的方式
  2. 与页面其他部分有关的行为方式。

通常,您创建 DOM 节点并将其附加至其他元素作为子项。 借助于 shadow DOM,您可以创建作用域 DOM 树,该 DOM 树附加至该元素上,但与其自身真正的子项分离开来。这一作用域子树称为影子树。被附着的元素称为影子宿主。 您在影子中添加的任何项均将成为宿主元素的本地项,包括 <style>。 这就是 shadow DOM 实现 CSS 样式作用域的方式。

shadow DOM 特点

  • 隔离 DOM:组件的 DOM 是独立的(例如,document.querySelector() 不会返回组件 shadow DOM 中的节点)。
  • 作用域 CSS:shadow DOM 内部定义的 CSS 在其作用域内。样式规则不会泄漏,页面样式也不会渗入。
  • 组合:为组件设计一个声明性、基于标记的 API。
  • 简化 CSS - 作用域 DOM 意味着您可以使用简单的 CSS 选择器,更通用的 id/类名称,而无需担心命名冲突。
  • 效率 - 将应用看成是多个 DOM 块,而不是一个大的(全局性)页面。

shadow DOM 的使用

创建一个 shadow DOM,继承自 HTMLElement,在构造函数可以创建和操作 dom

class ToolTip extends HTMLElement {
constructor() {
super();
var shadow = this.attachShadow({ mode: 'open' });
var header = document.createElement('h1');
header.className = 'shadow-dom-header';
header.innerHTML = 'shadow dom';
var style = document.createElement('style');
style.textContent = `.shadow-dom-header { color: red; }`;
shadow.appendChild(style);
shadow.appendChild(header);
}
}
customElements.define('tool-tip', ToolTip);

使用的方法跟原始的 html 标签一样

<tool-tip></tool-tip>

生成的 dom 结构和效果如下

shadow DOM 的样式是独立开的,不会受到外界的 class 的影响,内部也不会影响到外部的样式

slot 元素

Shadow DOM 使用 元素将不同的 DOM 树组合在一起。Slot 是组件内部的占位符,其实用法跟 vue 相似,可能是 vue 采用的这种思想哈。

如果 引入了元素,则这些元素可 “跨越” shadow DOM 的边界。 这些元素称为分布式节点。从概念上来看,分布式节点似乎有点奇怪。 Slot 实际上并不移动 DOM;它们在 shadow DOM 内部的其他位置进行渲染。

这句话比较难理解,我们先来尝试下如何使用 slot ,首先在上述的构造函数里面创建一个 slot

let slot = document.createElement('slot');
shadow.appendChild(slot);

使用 tool-tip 组件

<tool-tip>
 
<div>i'm a div</div>
</tool-tip>

可以看出 tool-tip 的子元素 div 会插在 shadow-root 的外部