神秘的 shadow-dom 浅析

摘要:
说到shadow-dom可能很多人会很陌生。shadow-root通过createShadowRoot返回的文档片段被称为shadow-root。更重要的是,Shadow-dom具有良好的密封性。那些不希望我们访问到的细节,则封装在了shadow-dom中。不幸的是,上面的控制方式只适用于chrome浏览器,虽然大部分现代浏览器已经支持shadow-dom,但是能够审查shadow-dom内部DOM元素的只有chrome浏览器,其他浏览器仍会把这些细节隐藏。shadow-dom兼容性shadow-dom的未来本文是非常基本的一些关于shadow-dom的概念,只是它的冰山一角,没有十分深入的去研究。

说到 shadow-dom 可能很多人会很陌生。但是其实我们肯定碰到过,本文主要想简单介绍下shadow-dom。下面直接进入正文。

shadow-dom 是什么

顾名思义,shadow-dom,直译的话就是影子dom?我觉得可以理解为潜藏在黑暗中的 DOM 结构,也就是我们无法直接控制操纵的 DOM 结构。前端同学经常用开发者工具的话,查看 DOM 结构的时候,肯定看到过下面这样的结构:

神秘的 shadow-dom 浅析第1张

这里的#shadow-root所包含的内容其实就是所谓的shadow-dom

shadow-dom其实是浏览器的一种能力,它允许在浏览器渲染文档(document)的时候向其中的 Dom 结构中插入一棵 DOM 元素子树,但是特殊的是,这棵子树(shadow-dom)并不在主 DOM 树中。

举个栗子,也是最常见的例子,<video>标签,我们创建在页面上创建一个空白的video标签:

<video id='test'></video>

查看 DOM 结构如下:

神秘的 shadow-dom 浅析第2张

虽然我们创建的是一个空标签,但是在这个空标签内部,存在一个shadow-dom,点开shadow-dom可以看到内有乾坤,大有内容。其实这内部的具体内容,就是<video>的具体实现。

shadow-dom 结构示意

再用一幅图总结一下:

神秘的 shadow-dom 浅析第3张

document

这个很好理解,就是我们的正常文档 document 。

shadow host

对于一个内部有shadow-dom的元素而言,它必然需要一个宿主元素,对于上面的例子而言,<video>标签,就是 shadow-dom 的宿主元素。

shadow-root

通过createShadowRoot(下文会提及) 返回的文档片段被称为 shadow-root 。它和它的后代元素,都将对用户隐藏,但是它们是实际存在的,在 chrome 中,我们可以通常审查元素去查看它们的具体 DOM 实现。

<video>中,例如暂停,播放,音量控制,全屏按钮,进度条等都是 shadow-root 的后代。它们工作时会显示在屏幕上,但他们的 DOM 结构对用户是不可见的。

contents

就是上述所说的<video>中各子组件的 DOM 的具体实现。

为什么需要 shadow-dom

为什么需要有这种结构呢?

Shadow-dom 是游离在 DOM 树之外的节点树,但是他的创建基于普通 DOM 元素(非 document),并且创建后的 Shadow-dom 节点可以从界面上直观的看到。更重要的是,Shadow-dom 具有良好的密封性。

这是浏览器提供的一种“封装”功能,提供了一种强大的技术去隐藏一些实现细节。什么意思呢?以w3c上的一个<video>例子为例,我们仅仅是填写了一个空白的标签,再加上src属性里填上视频地址,就可以播放视频了:

神秘的 shadow-dom 浅析第4张

我们仅仅填写了一行代码,却拥有比这行代码更多的功能,譬如暂停,播放,音量控制,全屏按钮,进度条等等。

这些功能具体的 DOM 实现,其实都在shadow-dom中:

神秘的 shadow-dom 浅析第5张

浏览器的开发者们意识到作为前端开发者,引用一个<video>标签的时候,每次还要写入一大堆 DOM 去控制控件的表现和行为,既不简洁也很困难。所以他们界定了这样一个界限,界定了哪些是你可以访问的,哪些实现细节是访问不到的。

那些不希望我们访问到的细节,则封装在了shadow-dom中。然而,浏览器本身却可以随意跨越这个边界。设置这样一个边界之后,浏览器的开发者们就可以在我们看不见的地方使用熟悉的web技术、同样的HTML元素去创建更多的功能,而不是像我们一样要在页面上用div和span来堆砌这些元素。

如何控制 shadow-dom

既然是浏览器开发者有意隐藏起来的 DOM 结构,那么我们是否可以控制内部的 DOM 结构呢?并非完全不可以,还是有一些方法使得我们可以控制shadow-dom内的一些表现。

使用伪元素控制 shadow-dom 样式

这里我们要使用到伪元素,通过伪元素,我们可以控制shadow-dom中 DOM 结构的样式。

在 chrome 下,查看shadow-dom结构(如果无法看到shadow-dom需要手动打开),可以看到每个结点都加上了一个 pesudo 属性:

神秘的 shadow-dom 浅析第6张

有了这些属性,我们可以通过伪元素的方式控制他们,譬如在一些场景下 video 标签的控制条不会自动隐藏或自动显示,可以通过伪元素指定默认显隐方式:

如果你在 chrome 浏览器下阅读本文,从上面的 codePen 可以看到,我使用伪元素修改了 video 控件条的底色为粉红色 deeppink。

不幸的是,上面的控制方式只适用于 chrome 浏览器,虽然大部分现代浏览器已经支持shadow-dom,但是能够审查shadow-dom内部 DOM 元素的只有chrome浏览器,其他浏览器仍会把这些细节隐藏。

使用 Javascript 创建一个 shadow-dom 元素

我们也可以通常 Javascript 创建shadow-dom,实现各类功能的封装,主要通过:

HTMLElement.prototype.createShadowRoot =
	HTMLElement.prototype.createShadowRoot ||
	HTMLElement.prototype.webkitCreateShadowRoot ||
	function() {};

看看下面这个例子,在chrome内核浏览器下,将创建一个简单的shadow-dom,将我们的代码放入一个template中,再通过importNode插入到shadow-dom中:

如果你现在在 chrome 内核浏览器下访问本文,那么上述的 codePen 中你应该可以看到 createShadowDomByJs 这一行文字,打开审查元素,会看到<p>结构是隐藏在shadow-dom中的。

shadow-dom 兼容性

神秘的 shadow-dom 浅析第7张

shadow-dom 的未来

本文是非常基本的一些关于shadow-dom的概念,只是它的冰山一角,没有十分深入的去研究。

现行的组件都是开放式的,即最终生成的 HTML DOM 结构难以与组件外部的 DOM 进行有效结构区分,样式容易互相混淆。Shadow-dom 的封装隐藏性为我们提供了解决这些问题的方法。在 Web 组件化的规范中也可以看到 Shadow-dom 的身影,使用具有良好密封性的 Shadow-dom 开发下一代 Web 组件将会是一种趋势。

更多资源及参考文章

如果你读完本文后仍然意犹未尽,可以看看下面这些文章:

到此本文结束,如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

免责声明:文章转载自《神秘的 shadow-dom 浅析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇android截图bat脚本[Go]将string转换为io.Reader类型下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

React中的虚拟DOM

我们知道,当组件的state和props发生变化的时候,render函数就会重新执行,组件就会被重新渲染,这样是性能非常低的。因此,react引入了虚拟DOM. 虚拟DOM是什么呢?虚拟DOM就是一个JS对象,用它来描述真实DOM。 当state发生变化时,render函数会重新执行渲染页面。如果我们自己来做这个功能,那该怎样实现呢? 方案一: 1. 定义...

vue源码实现的整体流程解析

一、前言 最近一直在使用vue做项目,闲暇之余查阅了一些关于vue实现原理的资料,一方面对所了解到的知识做个总结,另外一方面希望能对看到此文章的同学有所帮助。本文如有不足之处,还请过往的大佬批评指正。 二、vue实现原理概述 vue作为一个前端渐进式的MVVM开发库,将广大的前端劳苦大众从DOM操作中解放出来;说到vue的实现原理,大体可分为三个要素: 1...

python_14(js)

第1章 图片方法 1.1 设置背景图:1.2 背景图问题:1.3 background-repeat; noa-repe 1.4 background-attachment: fixed1.5 background-position 1.6 background-position-x 1.7 截取局部1.7.1 透明色第2章 定位 2.1 定义形式2.2...

XML知识总结

1、XML概念及作用? XML( eXtensible Markup Language,可扩展标记语言)是一种简单的数据存储语言 作用:用来存储和交换数据 无法描述页面的排版和显示形式 2、XML和XHTML的区别  1、XHTML 2、XML 标签  (1)标签都有固定含义 不能去创造新的标签          (2)支持自定义标签,具有扩展性 作用 ...

快速入门vue-render函数

render 函数,大部分工老油条,应该是比较了解了,但是可能有些初出茅庐的小年轻们,不是很了解,并且严老湿也去网上查阅了一些相关的文章,总结了一下,不够系统,所以今天简单聊一下,循环渐进 render 函数是什么 ​ 平常我们写 <template> 里面所使用模板HTML语法组建页面的,其实在 vue 中都会编译成 render 函数,因为...

全球最大的3D数据集公开了!标记好的10800张全景图

Middlebury数据集 http://vision.middlebury.edu/stereo/data/ KITTI数据集简介与使用https://blog.csdn.net/solomon1558/article/details/70173223 http://www.dataguru.cn/article-12197-1.html 摘要: 一路走...