ITPub博客

首页 > 应用开发 > Html/css > 黄琼:如何使用shadow DOM生成Web组件?

黄琼:如何使用shadow DOM生成Web组件?

原创 Html/css 作者:韩楠 时间:2022-06-07 18:44:15 0 删除 编辑


责编 | 韩楠

约  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节点。以下,就是我们上一节完成的 <my-element> 标签。



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



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


完整代码如下:



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



接着,我们试试用  document.getElementsByTagName('h1'), 去获取这个   <h1>  标签,会发现拿不到,符合预期。


如果我们真的要去操作,那就得用 shadow DOM 的 API。也就是说,常规的用DOM API的操作都是不可能会影响到shadow DOM的。


这就是实现隔离的原理。




style shadow DOM


创建好shadow DOM树之后,接下来我们给它点样式装修一下。这里跟常规的添加样式的方法一样,有两种方式,一种是使用 <style> 标签的内联样式,还有一种是通过 <link> 引入的外联样式。



内联样式

内联样式的方法:首先创建一个style标签,再设置好style标签里的内容即可。




效果如下:





外联样式


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



以上,就是两种style shadow dom节点的方法。这里要注意的是:shadow DOM里的样式是不受外界影响的,也不会影响外面的DOM节点, 也就是样式也具有隔离性。


下面我们来验证一下。


首先,在外层也定义同名的样式名my-style,这里设置它的字体颜色为绿色。而shadow DOM中的my-style设置字体为红色。



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



说明即使外面也定义了同名的classname,但是不会作用到shadow dom元素上, 所以shadow DOM中的样式是有隔离性的。





总结


到这里,我们就把自定义标签<my-element>封装起来了,它最大的特点就是隔离性。



其实,我们的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





来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70016482/viewspace-2899292/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2022-04-08

  • 博文量
    94
  • 访问量
    145405