持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
两类DOM tree
-
一个DOM元素通常包含两类DOM子树
- Light tree:一般的DOM树,由HTML子元素组成
- Shadow tree:一个隐藏的DOM子树,不在HTML中反应
如果一个元素同时拥有以上两种DOM子树,那么浏览器只渲染shadow tree。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script>
customElements.define('shadow-test', class extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = "这是Shadow DOM元素"
const div = document.createElement("div")
div.innerHTML = "这是Light DOM元素"
this.append(div)
}
});
</script>
<body>
<shadow-test></shadow-test>
</body>
</html>
同时存在shadow tree和light tree显示结果如下:
通常我们使用Shadow dom是在自定义元素中使用,目的是为了隐藏组件内部结构和有效样式
Shadow DOM概念
-
Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中——它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。
-
一些术语:
- Shadow host:一个常规 DOM节点,Shadow DOM 会被附加到这个节点上。
- Shadow tree:Shadow DOM内部的DOM树。
- Shadow boundary:Shadow DOM结束的地方,也是常规 DOM开始的地方。
- Shadow root: Shadow tree的根节点。
- 就像操作常规DOM一样,我们可以为shadow dom添加子节点,设置属性,以及添加样式,shadow dom内部的元素始终不会影响到外界元素(除了
:focus-within)。
内建Shadow DOM
- 一些复制的浏览器控件如:
<input>、<video>等,浏览器在内部DOM/CSS来绘制他们,而这个结构一般是隐藏的,我们不能使用一般的 JavaScript 调用或者选择器来获取内建 shadow DOM 元素。它们不是常规的子元素,而是一个强大的封装手段。
-
例如:input元素在Chrome浏览器中的表现为
基本用法
-
我们可以调用elem.attachShadow({mode: "opne"/"closed"})来创建一个shadow root
-
每个元素中只能有一个shadow root
-
elem必须是自定义元素,或者是以下元素中其中一个:
article、aside、blockquote、body、div、footer、h1、h1、h2、h3、h4、h5、h6、header、main、nav、p、section和span。其他元素则不能容纳shadow tree -
mode选择的值为open或者closed:
- open: shadow root 可以通过
elem.shadowRoot访问。例如可以使用elem.shadowRoot访问
let ShadowDom = customElem.shadowRoot;-
closed:
elem.shadowRoot永远是null。- 我们只能通过
attachShadow返回的指针来访问 shadow DOM(并且可能隐藏在一个 class 中)。 - 例如在原生中video,input是封闭的shadow dom 没有任何方法可以访问他们
- 我们只能通过
- open: shadow root 可以通过
-
-
shadow dom会和主文档分开
-
Shadow DOM 元素对于 light DOM 中的
querySelector不可见。实际上,Shadow DOM 中的元素可能与 light DOM 中某些元素的 id 冲突。这些元素必须在 shadow tree 中独一无二。 -
Shadow DOM 有自己的样式。外部样式规则在 shadow DOM 中不产生作用。
- 可以使用elem.style设置样式
- 也可以创建
<style>元素为shadow tree添加全局样式 - 还可以通过创建
<link>标签引入外部样式
// 将外部引用的样式添加到 Shadow DOM 上 const linkElem = document.createElement('link'); linkElem.setAttribute('rel', 'stylesheet'); linkElem.setAttribute('href', 'style.css'); // 将所创建的元素添加到 Shadow DOM 上 shadow.appendChild(linkElem);- 获取 shadow tree 内部的元素,我们可以从树的内部查询
- 拥有自己的id空间
-