
责编 | 韩楠
约 1898 字 | 4 分钟阅读
前言
之前我曾做过这样 一篇技术分享 ,侧重讲了如何去自定义html标签,有感兴趣的朋友可以看下。与此相关的,其实,里面还遗留了一个重要的问题点,我觉得很有必要单拎出来,今天就跟大家一起分享下。
就是如何将我们这个自定义的html标签封装好,可以做到像原生的video那样,自己的样式、结构以及js行为都不被外界影响,这样就不会因为外界的错误而造成组件bug了。
这一篇文章,我们使用shadow dom来封装这个自定义标签,实现与外界隔离的效果。
shadow DOM是什么
大家可能没听过shadow DOM,但是DOM应该都听过吧。那什么是DOM呢?MDN对于它的定义是这样的。

这里粗略翻译一下:就是说DOM就是web documents的一个编程接口,它可以将document转化成节点跟对象,这样编程语言,才可以去跟页面上的HTML元素进行交互,包括改变它的结构、样式和内容。
我个人的理解是:
浏览器会先将HTML结构解析为一个DOM树,每一个html元素都是这个对象里的一个DOM节点,然后DOM提供用来操作(包括增,删,改)HTML元素的方法,让用户可以操作里面所有的节点。比如,我们经常用到的getElementById 就是DOM给我们提供的通过id获取html元素的方法。
这套用来解析html结构,并且提供操作他们的API标准就是HTML DOM。
其实简单来说,你不管它的概念就是把它当成中介就行了。有了这个中介,我们才可以去获取和操作到页面的HTML元素。
这样以此类推,shadow DOM,就是用来操作 “shadom DOM 节点” 的 API 标准。 这个“shadom DOM节点”,就是我们今天的重点 ,它跟常规的DOM节点不同。
它最大的特点就是与常规DOM节点是隔离的,用普通的DOM API,比如getElementById去拿一个shadom DOM节点是拿不到的。
下面举一个例子:
前面说过浏览器会把html解析成DOM树,这里我们假设平平无奇的DOM树长这样。

接着我们再构建 shadow DOM 树,这里的 shadow 的根节点就叫 shadow root。它由一个shadow boundary 的虚拟边界跟外界隔着。

构建好之后,就需要挂到DOM树上的某个节点,这个被挂载的节点叫 shadow host。这里我们选取最右边这个DOM节点作为挂载的节点挂上去。你可以理解成像纽扣一样扣上去。

如此一来,整个树就合成了,合成之后的DOM树就长这样。我们可以看到,此时这颗DOM树有绿色的常规DOM节点,以及粉色的shadow DOM节点。

接下来看看代码要如何实现这样一颗树。
使用shadow DOM
前面说过,shadow DOM树必须要挂载在一个常规的DOM节点(shadow host)上,这里我们用
Element.attachShadow()
来创建shaodw DOM 树的根节点 shadow root。这里的Element 指的就是 shadow host。

参数mode,可以传open跟closed。
区别在于使用open的话,你可以用
let myShadowDom = myCustomElem.shadowRoot;
拿到shadow root,而closed不行的。
但是,通过一些hack的方式硬要拿也是可以拿到的,所以实际使用中我们就没必要用closed,open就够用了。
下面,来给我们之前自定义好的HTML标签,加上这个shadow root节点。以下,就是我们上一节完成的
标签。

我们的任务,就是把这个自定义标签里的DOM节点,在这里就是这个及其子节点,变成shadow DOM节点。

也很简单,首先创建shadow DOM树的根节点shadow root,然后构建到shadow DOM树的节点之后,再挂载到shadow root下即可。
完整代码如下:

到这里我们就完成啦。可以看到效果图里,
已经变成shadow DOM节点了。Hey, it's me

接着,我们试试用
document.getElementsByTagName('h1'),
去获取这个
标签,会发现拿不到,符合预期。
如果我们真的要去操作,那就得用 shadow DOM 的 API。也就是说,常规的用DOM API的操作都是不可能会影响到shadow DOM的。
这就是实现隔离的原理。
style shadow DOM
创建好shadow DOM树之后,接下来我们给它点样式装修一下。这里跟常规的添加样式的方法一样,有两种方式,一种是使用
标签的内联样式,还有一种是通过
引入的外联样式。
内联样式的方法:首先创建一个style标签,再设置好style标签里的内容即可。

效果如下:

外联样式
外联样式的方法:创建
标签插入。

以上,就是两种style shadow dom节点的方法。这里要注意的是:shadow DOM里的样式是不受外界影响的,也不会影响外面的DOM节点, 也就是样式也具有隔离性。
下面我们来验证一下。
首先,在外层也定义同名的样式名my-style,这里设置它的字体颜色为绿色。而shadow DOM中的my-style设置字体为红色。

我们可以看到,即使是相同的样式名,外层的DOM 节点
显示的是绿色,内层还是显示红色。

说明即使外面也定义了同名的classname,但是不会作用到shadow dom元素上,
所以shadow DOM中的样式是有隔离性的。
总结
到这里,我们就把自定义标签

其实,我们的web components一样可以使用Vue来完成,大家感兴趣的话,后面我们可以一起来看看vue components跟 web components的区别,以及如何使用Vue来完成一个web component。
今天的分享到这里就结束了,希望今天你可以有一定收获。如果对今天的内容有共鸣,也可以分享给你的朋友。我们可以留言区里一起继续交流、讨论。
参考资料:
更多文档请参考 Using shadow DOM
( 链接:https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM)
THE END
转载请联系ITPUB官方公众号获得授权
—————————————————————————————————
欢迎各领域技术人员投稿
投稿邮箱 | hannan@it168.com