Shadow DOM摘要

近期看了看Shadow DOM相关的一些资料和[规范](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html),记录一些摘要和自己的看法。
## 作用
在文档中创建一个**独立**的子文档环境,但又可以通过特定的方法与主文档进行**元素的交换**
## 核心概念
- `createShadowRoot()`函数创建子文档- **insertion point**进行元素交换- 元素交换有一个匹配过程,称为**matching**,这过程中使用CSS选择器进行- 一个元素可以被多个**insertion point**引用,称为**reprojection**- **shadow insertion point**进行子文档的聚合,称为**composition**,把一个子文档聚合到另一个文档上的过程称为**assign**- 子文档中可以使某个元素变为伪元素,使用**pseudo**属性,且值必须以**x-**开始- 主文档可以通过元素的`shadowRoot`拿到子文档的document并使用,不存在cross domain问题- 使用**reference combinator**去获取关联到**insertion point**的元素,方法是`{insertion-point-selector} /select/ {element-selector}`,这样可以主文档传入一个`<input>`,子文档修改其value来制作一些诸如日历等的组件
## 现有实现
- Chrome >= 25部分实现此功能,各函数加`webkit`前缀- **matching**中可以使用的一些伪类,在Chrome中有奇怪表现,如`:visited`会找到所有的`<a>`元素,无论是否被访问过,而`:target`伪类似乎没用- **insertion point**对应的是`<content>`元素,可以使用`select`属性来声明**matching**的选择器,如`<content select=".name"></content>`- **shadow insertion point**对应的是`<shadow>`元素- Chrome好像暂时不支持**reference combinator**,所以现阶段子文档别想和父文档交互- 不知道拿到**insertion point**上关联的元素后,能不能用`appendChild`等方法来进行XSS,能的话Shadow Root意义会降低很多- 由于是2个文档,selection和range的行为会变得很奇怪- 不过TAB导航倒是没有问题,配合事件模型这一块,有一个重定向的概念
## 想法
Shadow DOM的目标是创建一个相对独立的环境,在这个环境中的内容和交互并不会影响到其外部环境,称为“封装”。
但是一个功能,从不同的角度来看的话,似乎会有不同的需求。
从页面制作者的角度来看:
1. 不支持Shadow DOM的环境下可以良好地降级,这一点基本满足,因为**insertion point**交换的元素都定义在外面2. 子文档不得影响主文档,以免被进行XSS攻击,这一点满足
从子文档(想不到好的词,打算叫Widget)作者的角度来看:
1. 希望可以不用担心自己的Widget在什么环境下使用,这一点满足,Shadow DOM和一个普通的文档几乎一样,不用担心**不小心访问到外面**2. 希望使用自己Widget的环境不要像hacker一样来读、写自己的内容,很遗憾这一点**无法满足**,外部可以通过`shadowRoot`访问整个子DOM,进行任意的读和写操作
从第三方内容提供商(如广告)的角度来看:
1. 希望样式隔离、交互隔离,这一点满足2. 希望自己的数据、内容不会被监控,这一点**无法满足**,同样通过`shadowRoot`可以拿到所有的数据3. 相比`<iframe>`,希望可以支持更好的动态效果,如让元素在屏幕中飘来飘去,这一点**无法满足**,子文档是独立的文档环境,多数动画依赖的绝对定位和`overflow: visible;`无法实现
因此,大致会变为以下情况:
- 页面作者希望使用Shadow DOM引入第三方的Widget- Widget作者偏向使用Shadow DOM- 第三方内容提供商继续使用`<iframe>`以利用其跨域的权限控制,对Shadow DOM不感兴趣
## 我想要有的东西
Shadow DOM相当完善,唯一的遗憾是提供了一个入口,让主文档可以去访问及修改子文档。这非常明显地破坏了**封装**的概念,所谓**对修改关闭,对扩展开放**的理念完全没有体现出来。
因此,如果在Shadow DOM的基础上,可以有选择地去掉`shadowRoot`的过分的权限,使用一种受限的模型进行主、子文档的交互,将会有更多的人收益,大致想法如下:
- 在`createShadowRoot()`时,可以给**ShadowRoot**对象添加一个属性,如sandbox,以控制主文档不可以访问子文档,形成一个完全隔绝的沙箱- 主、子文档间提供类似`postMessage`的机制进行通信,以便子文档提供受限和可控的API
## 总结
总之Shadow Root可以认为是一个沙箱,沙箱中的内容不能影响外部。但是外部却可以访问内部的东西,因此又不是一个完整的沙箱,从Widget和第三方内容开发者的角度来看,并不是特别好用的东西。
另外,怎么才能移除或销毁一个Shadow Root?
 		 	   		  

Received on Wednesday, 23 January 2013 03:01:16 UTC