标签:
Web Components 系列主要由自定义元素(Custom Elements)、HTML 引入(HTML Imports)和影子 DOM(shadow DOM) 组成,而 Shadow DOM 无疑是当中的重中之重。本文对下面翻译的几篇文章进行综述,总结了 Shadow DOM 术语梳理和结构关系。
影子 DOM(shadow DOM):是一种依附于文档原有节点的子 DOM,具有封装性
光明 DOM(light DOM):就是原生的 DOM,为了与影子 DOM 区别采用的名词
影子树(shadow trees):特指存在于 shadow DOM 中的节点结构
影子宿主(shadow host):特指 shadow DOM 所依附的影子宿主,是存在于原生 DOM 中的节点
影子根(shadow root):指 shadow DOM 的根节点
插入点(insertion point):指 shadow DOM 中的 <content>
标签
贪心插入点(greedy insertion point):指使用通配符选择器进行匹配的插入点
影子边界(shadow boundary):指对影子 DOM 与光明 DOM 进行的样式隔离,两者中的样式不会相互影响。
分布节点(distributed nodes):指原本存在于光明 DOM 结构中,被 <content>
标签添加到影子 DOM 中的节点。
影子 DOM 必须依附于一个文档中的原有 DOM 节点,也就是影子宿主,而影子 DOM 中的节点也可以成为另一个影子树的宿主。在 Web Components 的实际使用场景中,宿主一般是自定义元素,而在影子 DOM 中封装了其实现细节。
影子 DOM 树被影子边界所包裹,边界给其带来了封装性,这一封装性包括:
DOM 的封装性:在不同的 DOM 树中无法选择另外 DOM 中的元素,只有获取对应的 DOM 树才能对其中的元素进行操作;
样式的封装性:在不同的 DOM 树中样式无法相互影响,只有通过一系列手段突破边界才能对对方的样式进行操作。其中通过影子 DOM 来对宿主 DOM 进行操作的方式多种多样:
需要注意的是,单独使用 ::content
选择器没有意义,这表示对插入点进行的样式修饰,而插入点是不展现的;所以该选择器的出现必然跟随者子选择器,以便对分布节点进行样式影响。
而光明 DOM 对于影子 DOM 的影响却要弱很多,且原则上来讲,影子 DOM 存在的意义就是为了对子 DOM 进行封装,而实现自定义元素对外部隐藏细节的效果。如果用户要求进行影响的话,这里也存在两个大杀器:一层穿透 ::shadow
伪类选择器与多重穿透 /deep/
组合符。
对宿主本身进行样式影响:通过 :host
选择器
对宿主的祖先节点进行样式影响:通过 :host-context
选择器
对分布节点进行影响:通过 ::content
选择器
JS 的重定向与阻塞:影子边界对于 JS 的阻塞是最弱的,它仅仅阻塞了一部分事件, 同时将影子 DOM 中的事件重定向到宿主上。关于事件重定向,Eric Bidelman 的 Shadow DOM 301 讲的更为细致一点,事实上重定向仅仅是表示影子 DOM 中的事件冒泡无法通过影子边界,而在边界内部的事件监听还是有效果的。我们也可以通过 event.path
来查看调整后的事件路径,并找到事件在影子 DOM 中的真正源头。
光明 DOM 与影子 DOM 的结构关系如下图所示:
图中蓝线表示样式影响方式,红线表示 DOM 影响方式,黄线表示 JS 影响方式。
在影子 DOM 中,<link>
标签时被忽略的,因此不能用外链的方式引入 CSS 文件。在 Polymer 中我们可以这样做,是因为 Polymer 将 <link>
节点转化为了 <style>
节点所致。在原生的实现上要注意这一点。
标签:
原文地址:http://my.oschina.net/1pei/blog/490862