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
标签不一样,它们就简单写个标签就能渲染出对应的样式与功能;
或者有些同学理解成这都是底层渲染的事,我们不必关心。
是的,这些标签内部的内容确实都是底层渲染的,不过我们也不是看不到它们内部的实现原理。
查看html原生标签的Shadow DOM
在html中写入以下标签,然后到浏览器控制台去查看
<input type="text">
<input type="range">
<video src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" controls></video>
<textarea></textarea>
很多人看到的是这样的,但这和我们写的没有任何区别呀?别急,这就带你看看他们的真实面目~
首先打开浏览器控制台的设置选项
然后再找到Preference -> Elements,把show user anent shadow dom勾上
这时候我们再来看一下此时的dom元素发生了什么变化
我们会发现这些标签内部都大有乾坤,在这些标签下面都多了一个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
的结构以及它与真实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 = `
<div>前端南玖</div>
`
shadowroot.innerHTML
shadow dom mode
当调用Element.attachShadow()
方法t时,必须通过传递一个对象作为参数来指定shadow DOM树的封装模式,否则将会抛出一个TypeError
。该对象必须具有mode
属性,值为 open
或 closed
。
-
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的特点
从前面的介绍,我们知道shadow dom是游离在 DOM 树之外的节点树,但是它是基于普通 DOM 元素(非 document)创建的,并且创建后的 Shadow-dom 节点可以从界面上直观的看到。最重要的一点是Shadow-dom 具有良好的密封性。
样式
<style>.wx_name {
color:aqua;
}
</style>
<body>
<div class="wx_name">我是真实dom</div>
<div id="root"></div>
<script>const shadowroot = root.attachShadow({mode: 'open'})
const template = `
<div class="wx_name">shadow dom - 前端南玖</div>
`
shadowroot.innerHTML</script>
</body>
它渲染出来是下面这样的
标签:DOM,dom,标签,元素,Shadow,root,shadow,究竟 From: https://blog.51cto.com/u_13756259/5797935