什么是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 使用 <slot> 元素将不同的 DOM 树组合在一起。Slot 是组件内部的占位符,其实用法跟 vue 相似,可能是 vue 采用的这种思想哈。

如果 <slot> 引入了元素,则这些元素可 “跨越” 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 的外部