
浅谈 ShadowDOM
为什么会有 Shadow DOM
你在实际的开发中很可能遇到过这样的需求:实现一个可以拖拽的滑块,以实现范围选择、音量控制等需求。
除了直接用组件库,聪明的你肯定已经想到了多种解决办法。如在数据驱动框架 React/Vue/Angular 下,你可能会找到或编写对应的组件,通过相应数据状态的变更,完成相对复杂的交互;如在小快灵的项目下,用 jQuery 的 Widget 也是一个不错的选择;在或者,你可以点开你的 HTML + JavaScript + CSS 技能树,纯手工打造一个。这都是不难完成的任务。
当然,在完成之后,你可能会考虑对组件做一些提炼,下次再遇到同样的需求,你就可以气定神闲地“开箱即用”。Clair 组件库对这个需求的封装。
我们不妨从这个层面再多想一步。其实由于 HTML 和 CSS 默认都是全局可见的,因此,尤其是纯手工打造的组件,其样式是很容易受到所在环境的干扰的;由于选择器在组件层没有统一的保护手段,也会造成撰写时候的规则可以被随意修改;事件的捕获和冒泡过程会和所在环境密切相关,也可能会引起事件管理的混乱。
根据一般意义上“封装”的概念,我们希望相对组件来讲,DOM 和 CSS 有一定的隐藏性;如非必要,外部的变化对于内部的有一定的隔离;同时,外界可以通过且仅可以通过一些可控的方法来影响内部,反之亦然。
针对这些问题,其实浏览器提供了一种名叫 Shadow DOM 的解决方案。这个方案目前与 Custom Elements、HTML Templates、CSS changes 和 JSON, CSS, HTML Modules 并列为 Web Components 标准。
Shadow DOM 的概念
我们仍以上面的滑块作为例子。在最新的 Chrome 浏览器上,你可以输入如下代码来实现上面的功能:
<input type="range" disabled min="20" max="100" defaultValue="30" />
请打开 DevTools 中的“show user agent shadow DOM”:
在 DevTools 的 Elements 标签中,我们可以看到这个“组件”的实现细节。