Shadow DOM
Web components 的一个重要属性是封装——可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。其中, Shadow DOM 接口是关键所在,它可以将一个隐藏的、独立的 DOM 附加到一个元素上 [ MDN ] 。
当我们对 DOM(文档对象模型)有一定的了解,它是由不同的元素节点、文本节点连接而成的一个树状结构,应用于标记文档中(例如 Web 文档中常见的 HTML 文档)。请看如下示例,一段 HTML 代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Simple DOM example</title>
</head>
<body>
<section>
<img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth.">
<p>Here we will add a link to the <a href="https://www.mozilla.org/">Mozilla homepage</a></p>
</section>
</body>
</html>
这个片段会生成如下的 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的根节点。
准备工作
需求分析
常规的 alert 一般是一个 粘性布局 & 层级较高 的盒子,它能够被任意页面 / 组件 调用,它不应该被同时多次调用。
盒子包含三块内容:消息图标、消息文本、关闭btn。
设计思路
插件的设计思路是有良好的封闭性,不影响外部文档本身的DOM树;易于维护,便于需求更改,在下一个项目中重复使用;足够灵活,通过传入参数配置组件在不同文档中的调用效果;能够定制,可以通过外部文档调整插件。
-
结合 ShadowDom 的知识点,实现一个 alert 已见雏形。
Shadow DOM的基本使用
使用 Element.attachShadow()
方法来将一个 shadow root 附加到任何一个元素上。它接受一个配置对象作为参数,该对象有一个 mode
属性,值可以是 open
或者 closed
:
let shadow = elementRef.attachShadow({mode: 'open'});
let shadow = elementRef.attachShadow({mode: 'closed'});
两者的区别在于能否通过 shadow.shadowRoot 访问 shadowDOM 中的元素。
{ mode: 'open' } :可以通过页面内的 JavaScript 方法来获取 Shadow DOM
{ mode: 'closed' } :不能从外部获取 Shadow DOM , Element.shadowRoot 将会返回 null。
浏览器中的某些内置元素就是如此,例如 <video> ,包含了不可访问的 Shadow DOM。
将 Shadow DOM 附加到一个元素之后,就可以使用 DOM APIs对它进行操作,就和处理常规 DOM 一样。
var para = document.createElement('p');
shadow.appendChild(para);
etc.
设计Alert
首先构造一个 Shadow DOM :
class MessageBox extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' })
}
}
行1 - extends关键字用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类 [ MDN ]。
行2 - 构造函数属于被实例化的特定类对象 。构造函数初始化这个对象,并提供可以访问其私有信息的方法。构造函数的概念可以应用于大多数面向对象的编程语言。本质上,JavaScript 中的构造函数通常在类的实例中声明 [ MDN ]。
行3 - super关键字用于访问和调用一个对象的父对象上的函数。在构造函数中使用时,super
关键字将单独出现,并且必须在使用this
关键字之前使用。super
关键字也可以用来调用父对象上的函数 [ MDN ]。
行4 - Shadow DOM 的方法属性,用于将一个 shadow root 添加到 instance class 上。