文章目录
一、Shadow DOM简介
Shadow DOM能够将一个隐藏的、独立的DOM附加到一个元素上。它可以保证元素功能的私有,这样就可以作为一个组件被其他页面引用,而不与外部发生冲突。
题外话:Shadow DOM对我们来说其实并不陌生,浏览器很久以前就在用它封装元素内部结构。
如何查看:
第一步:在页面内写入一个input
标签一个video
标签
第二步:通过浏览器打开
第三步:(按F12
)打开开发者工具进行如下设置
就能够发现原来这些标签的内部乾坤就是用Shadow DOM来实现的👍
二、Shadow DOM与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的根节点。
三、在Web Components中的基本用法
可以使用 Element.attachShadow()
方法来将一个 shadow root 附加到任何一个元素上。它接受一个配置对象作为参数,该对象有一个 mode
属性,值可以是 open
或者 closed
:
let shadow = elementRef.attachShadow({mode: 'open'});
let shadow = elementRef.attachShadow({mode: 'closed'});
// 将Shadow DOM附加到custom element上,可以在custom element的构造函数中添加如下代码(shadow DOM最实用的用法)
let shadow = this.attachShadow({mode: 'open'});
-
open
表示可以通过页面内的 JavaScript 方法来获取 Shadow DOM。 -
closed
表示不可以从外部获取,浏览器中的某些内置元素就是如此。通过js方法获取 Shadow DOM
let myShadowDom = myCustomElem.shadowRoot;
将 Shadow DOM 附加到一个元素之后,就可以使用 DOM APIs对它进行操作,就和处理常规 DOM 一样。
基本使用示例:
let shadow = this.attachShadow({mode: 'open'});
var para = document.createElement('p');
shadow.appendChild(para);
四、使用Web Components和shadow dom实现简单功能
实现一个鼠标滑过图标展示提示信息的功能
效果: ↓↓↓
// 1. 定义继承自HTMLElement的PopPopUpInfo类
class PopUpInfo extends HTMLElement {
// 2. 在构造函数中定义元素所有功能
constructor() {
// 3. 必须首先调用 super方法
super();
// 4. 创建shadow root
var shadow = this.attachShadow({ mode: "open" });
// 5. 创建 shadow DOM 结构
// 5.1 创建 span
var wrapper = document.createElement("span");
wrapper.setAttribute("class", "wrapper");
var icon = document.createElement("div");
icon.setAttribute("class", "icon");
icon.innerText = "?";
var info = document.createElement("span");
info.setAttribute("class", "info");
// 5.2 获取属性的内容并将内容添加到 info 元素内
var text = this.getAttribute("text");
info.textContent = text;
// 6. 为 shadow DOM 添加一些 CSS 样式
var style = document.createElement("style");
style.textContent = `
.wrapper {
position: relative;
}
.info {
font-size: 0.8rem;
width: 200px;
display: inline-block;
border: 1px solid black;
padding: 10px;
background: white;
border-radius: 10px;
opacity: 0;
transition: 0.6s all;
position: absolute;
bottom: 6px;
left: 16px;
z-index: 3;
}
.icon {
width: 20px;
height: 20px;
margin-top: 100px;
background-color: #888;
border-radius: 10px;
text-align: center;
color: #FFF;
}
.icon:hover + .info {
opacity: 1;
}
`;
// 7. 将所创建的元素添加到 Shadow DOM 上
shadow.appendChild(style);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
// 8. 定义新的元素
customElements.define("popup-info", PopUpInfo);
对上述代码进行优化:
-
简化定义过程,将
class popupInfo extends HTMLElement{...}
与customElements.define("popup-info", popupInfo)
合并为:customElements.define( "popup-info", class extends HTMLElement {...})
-
将通过
document.createElement
、setAttribute
、appendChild
等实现的css样式及html结构,改为直接通过html格式书写,语义性更强,更符合书写习惯。
// 1. 简化定义过程
customElements.define(
"popup-info",
class extends HTMLElement {
// 2. 在构造函数中定义元素所有功能
constructor() {
// 3. 必须首先调用 super方法
super();
// 4. 创建shadow root
const shadow = this.attachShadow({ mode: "open" });
// 5. 通过innerHTML形式,创建 shadow DOM 结构
let htmlStr = `
<style>
.wrapper {
position: relative;
}
.info {
font-size: 0.8rem;
width: 200px;
display: inline-block;
border: 1px solid black;
padding: 10px;
background: white;
border-radius: 10px;
opacity: 0;
transition: 0.6s all;
position: absolute;
bottom: 6px;
left: 16px;
z-index: 3;
}
.icon {
width: 20px;
height: 20px;
margin-top: 100px;
background-color: #888;
border-radius: 10px;
text-align: center;
color: #FFF;
}
.icon:hover + .info {
opacity: 1;
}
</style>
<span class="wrapper" id="wrapper">
<div class="icon">?</div>
<span class="info" id="info"></span>
</span>
`;
// 6. 将创建的Shadow DOM添加到shadow root上
shadow.innerHTML = htmlStr;
// 7. 获取属性的内容并将内容添加到 info 元素内
/* 注意!!采用此种注册形式时一定要在加载完html后
才能通过shadowRoot获取元素并进行操作 */
var text = this.getAttribute("text");
let info = this.shadowRoot.children.wrapper.children.info;
info.innerHTML = text;
}
}
);
五、参考链接
MDN: Web Components:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components