Shadow DOM

最近在尝试做公司的前端组件化,采用自创的CBC(Classname Based Components)模式。今天学习了一下 Web Components 规范的其中一个组成部分,Shadow DOM,也算为今后的组件化之路进行铺垫吧。

什么是 Shadow DOM?

Shadow DOM 在我们开发组件的时候弥补了DOM树封装性不足的缺点。通过Shadow DOM,HTML Element可以获得一种新的节点,这种新的节点被称为shadow root,而拥有 shadow root 的 Element 被称为 shadow host

shadow host 的内容不会被渲染至页面,取而代之的是 shadow root 中的内容。

Shadow DOM 的构成

Shadow DOM包含三个概念,light DOM, shadow DOM, composed DOM。light DOM及shadow DOM 是实际编程时程序员写的代码,而composed DOM才是浏览器实际渲染的DOM元素。

light DOM

以下是一个自定义元素 <my-custom-element> 所用的 light DOM:

<my-custom-element>
  <q>Hello World</q> <!-- part of my-custom-element's light DOM -->
</my-custom-element>

<my-custom-element> 的 light DOM 对用户是可见的,它拥有 .childNodes, .children, .innerHTML 及一些可以提供其他子节点信息的属性或方法。

shadow DOM

<my-custom-element> 可以通过构造shadow root的形式定义自身的shadow DOM。

#shadow-root
  <!-- everything in here is my-custom-element's shadow DOM -->
  <span>People say: <content></content></span>
  <footer>sometimes</footer>

shadow DOM在元素的内部,对用户是不可见的,它的节点不是 <my-custom-element>children 节点。

使用方法:

var el = document.createElement('div');
var shadow = el.createShadowRoot(); // 在此实例化一个 shadow root
shadow.innerHTML = '<content select="q"></content>';
document.body.appendChild(el);

composed DOM

composed DOM是浏览器实际渲染出的元素,在渲染的时候,light DOM 会被融合进 shadow DOM,从而产生实际显示的 composed DOM。最终的显示看起来跟这个差不多:

<my-custom-element>
  <span>People say: <q>Hello World</q></span>
  <footer>sometimes</footer>
</my-custom-element>

在 light DOM 或 shadow DOM 中的节点只描述他们各自树形结构的主从关系,而实际存在composed 中的主从关系,不会在任何地方显示出来。所以,最终显示出来的 <span>看上去是 <my-custom-element> 的子节点以及 <q> 的父节点,但它实际上是 shadow root 的子节点,而且 <q><my-custom-element> 的子节点,这两个节点没有任何关系,只不过 Shadow DOM 把他们搞得像有关系似得。通过此种手段,用户可以像对普通DOM树一样直接操作 light DOM 或者 shadow DOM,而同步更新视图的工作交给系统来就可以了。

参考资料

  1. 《Shadow DOM》 - http://webcomponents.org/polyfills/shadow-dom/