究竟什么是Shadow DOM?

shadow dom 是什么?

顾名思义,shadow dom直译的话就是影子dom,但我更愿把它理解为DOM中的DOM。因为他能够为Web组件中的 DOM和 CSS提供了封装,实际上是在浏览器渲染文档的时候会给指定的DOM结构插入编写好的DOM元素,但是插入的Shadow DOM 会与主文档的DOM保持分离,也就是说Shadow DOM不存在于主DOM树上。

并且Shadow DOM封装出来的DOM元素是独立的,外部的配置不会影响到内部,内部的配置也不会影响外部。

如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,文章公众号首发,关注 前端南玖 第一时间获取最新文章~

思考

理解完它的概念,我们再来思考一个问题:

为什么我们用的一些标签明明就是一个空元素,但他却能够渲染出各种复杂的场景?

  • input
  • video
  • audio
  • textarea
  • 等...

可能很多同学都没想过为什么这些标签跟我们常用的div标签不一样,它们就简单写个标签就能渲染出对应的样式与功能;

或者有些同学理解成这都是底层渲染的事,我们不必关心。

究竟什么是Shadow DOM?插图

是的,这些标签内部的内容确实都是底层渲染的,不过我们也不是看不到它们内部的实现原理。

查看html原生标签的Shadow DOM

在html中写入以下标签,然后到浏览器控制台去查看





究竟什么是Shadow DOM?插图1

很多人看到的是这样的,但这和我们写的没有任何区别呀?别急,这就带你看看他们的真实面目~

首先打开浏览器控制台的设置选项

究竟什么是Shadow DOM?插图2

然后再找到Preference -> Elements,把show user anent shadow dom勾上

究竟什么是Shadow DOM?插图3

这时候我们再来看一下此时的dom元素发生了什么变化

究竟什么是Shadow DOM?插图4

我们会发现这些标签内部都大有乾坤,在这些标签下面都多了一个shadow root,在它里面才是这些标签的真实布局。

既然这些标签内部都有一些子元素布局,那么我们能不能通过JavaScript来访问到它们呢?

const input = document.querySelector('input')
console.log(input.firstChild)  // null

很明显,这是不可以的!

因为它为web开发者设定了一个边界,界定了哪些是你可以访问的,哪些实现细节是访问不到的。然而,浏览器本身却可以随意跨越这个边界。设置这样一个边界之后,它们就可以在你看不见的地方使用熟悉的web技术、同样的HTML元素去创建更多的功能,而不是像你一样要在页面上用div和span来堆。

shadow dom 结构

Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中——它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。

就是因为这个特点所以我们才能看到上面那些单个空标签就能够渲染出各种各样的复杂场景。

究竟什么是Shadow DOM?插图5

上面这张图非常直观的表现了shadow dom的结构以及它与真实dom的关系。

shadow host

一个常规 DOM 节点,Shadow DOM 会被附加到这个节点上。

shadow bounday

Shadow DOM 结束的地方,也是常规 DOM 开始的地方。

shadow tree

Shadow DOM 内部的 DOM 树。

shadow root

Shadow tree 的根节点。

如何使用shadow dom?

创建一个shadow dom

我们可以使用attachShadow给指定元素挂载一个shadow dom,并且返回对shadow root的引用。

const shadowroot = root.attachShadow({mode: 'open'})
const template = `
  
前端南玖
` shadowroot.innerHTML = template

shadow dom mode

当调用Element.attachShadow()方法t时,必须通过传递一个对象作为参数来指定shadow DOM树的封装模式,否则将会抛出一个TypeError。该对象必须具有mode属性,值为 openclosed

  • open shadow root 元素可以从 js 外部访问根节点,例如使用 Element.shadowRoot:
element.shadowRoot; // 返回一个 ShadowRoot 对象
  • closed 拒绝从 js 外部访问关闭的 shadow root 节点
element.shadowRoot; // 返回 null

浏览器通常用关闭的 shadow roo 来使某些元素的实现内部不可访问,而且不可从JavaScript更改。

对于一些不希望公开shadow root 的Web组件来说,封闭的shadow DOM看起来非常方便,然而在实践中绕过封闭的shadow DOM并不难。但是完全隐藏shadow DOM所需的工作量也大大超过了它的价值。

哪些元素可以挂载shadow dom?

这里需要注意的是并非所有html元素都可以挂载shadow dom,只有以下这些元素可以充当shadow dom的 shadow host

article aside blockquote body
div footer h1 h2
h3 h4 h5 h6
header main nav p
section span 任何带有有效的名称且可独立存在的自定义元素

当我们尝试在其它元素挂在shadow dom时,浏览器则会抛出异常。

const input = document.querySelector('input')
const inputRoot = input.attachShadow({mode: 'open'})

究竟什么是Shadow DOM?插图6

shadow dom的特点

从前面的介绍,我们知道shadow dom是游离在 DOM 树之外的节点树,但是它是基于普通 DOM 元素(非 document)创建的,并且创建后的 Shadow-dom 节点可以从界面上直观的看到。最重要的一点是Shadow-dom 具有良好的密封性。

样式



    
我是真实dom

`
shadowroot.innerHTML = template

它渲染出来是下面这样的👇:

究竟什么是Shadow DOM?插图7

上面我们说了shadow dom是游离在 DOM 树之外的节点树,所以我们文档上的CSS就不会作用在他身上。

样式化host元素

host伪类选择器允许你从shadow root中的任何地方访问shadow host

const shadowroot = root.attachShadow({mode: 'open'})
const template = `
       
shadow dom - 前端南玖
` shadowroot.innerHTML = template

究竟什么是Shadow DOM?插图8

需要注意的是:host仅在shadow root中有效,并且在shadow root之外定义的样式规则比:host中定义的规则具有更高的特殊性。

样式钩子

shadow dom还有一个非常重要的一个特点就是可以使用CSS自定义属性来创建样式占位符,并允许用户填充。


文章来源于互联网:究竟什么是Shadow DOM?

THE END
分享
二维码