基本构件介绍
Web Components旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。
- Custom elements(自定义元素):一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们。
- Shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
- HTML templates(HTML模板):
<template>
和<slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
HTML templates
<slot>
元素只能在 <template>
元素中使用,在 <template>
元素外表现和 <div>
元素一致。
Shadow DOM
shadowRoot mod
打开的shadow root允许你使用host元素的 shadowRoot
属性从 root 外部访问 shadow root 的元素,如下例所示:
<div>
<p>Light DOM</p>
</div>
<div id="host"></div>
<script>
const elem = document.querySelector('#host');
// attach an open shadow root to #host
const shadowRoot = elem.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `<p>Shadow DOM</p>`;
// Nodes of an open shadow DOM are accessible
// from outside the shadow root
elem.shadowRoot.querySelector('p').innerText = 'Changed from outside the shadow root';
elem.shadowRoot.querySelector('p').style.color = 'red';
</script>
但是如果 mode 属性的值为“closed”,则尝试从 root 外部用 JavaScript 访问 shadow root 的元素时会抛出一个 TypeError
。
并非所有 HTML 元素都可以托管 Shadow DOM DOM
下表列出了支持的元素:
- article
- article
- blockquote
- div
- h1-h6
- body
- footer
- header
- main
- nav
- p
- section
- span
尝试将 Shadow DOM 树附加到其他元素将会导致 DOMException 错误。
浏览器自动将shadow DOM附加到某些元素
Shadow DOM已存在很长一段时间了,浏览器一直用它来隐藏元素的内部结构,比如<input>
,<textarea>
和<video>
。
在自定义元素上托管shadow DOM
Custom Elements API 创建的自定义元素可以像其他元素一样托管shadow DOM。请看以下示例:
<my-element></my-element>
<script>
class MyElement extends HTMLElement {
constructor() {
// must be called before the this keyword
super();
// attach a shadow root to <my-element>
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>p {color: red}</style>
<p>Hello</p>`;
}
}
// register a custom element on the page
customElements.define('my-element', MyElement);
</script>
此代码了创建一个托管shadow DOM的自定义元素。它调用了 customElements.define()
方法,元素名称作为第一个参数,类对象作为第二个参数。该类扩展了 HTMLElement
并定义了元素的行为。
在构造函数中,super()
用于建立原型链,并且把 Shadow root 附加到自定义元素。当你在页面上使用 <my-element>
时,它会创建自己的 Shadow DOM:
请记住,有效的自定义元素不能是单个单词,并且名称中必须包含连字符( - )。例如,myelement 不能用作自定义元素的名称,并会抛出 DOMException
错误。
样式化 host 元素
shadow host 表示shadow DOM子树的根节点
CSS 伪类与自定义元素特别相关的伪类:
:defined
: 匹配任何已定义的元素,包括内置元素和使用CustomElementRegistry.define()
定义的自定义元素。:host
: 选择 shadow DOM 的 shadow host ,内容是它内部使用的 CSS( containing the CSS it is used inside )。:host()
: 选择 shadow DOM 的 shadow host ,内容是它内部使用的 CSS (这样您可以从 shadow DOM 内部选择自定义元素)— 但只匹配给定方法的选择器的 shadow host 元素。:host-context()
: 选择 shadow DOM 的 shadow host ,内容是它内部使用的 CSS (这样您可以从 shadow DOM 内部选择自定义元素)— 但只匹配给定方法的选择器匹配元素的子 shadow host 元素。
生命周期回调
定义在自定义元素的类定义中的特殊回调函数,影响其行为:
connectedCallback
:当自定义元素第一次被连接到文档 DOM 时被调用。disconnectedCallback
:当自定义元素与文档 DOM 断开连接时被调用。adoptedCallback
:当自定义元素被移动到新文档时被调用。attributeChangedCallback
:当自定义元素的一个属性被增加、移除或更改时被调
API
CustomElementRegistry
使用 CustomElementRegistry.define()
方法注册您的新自定义元素 ,并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。CustomElements
接口返回一个 CustomElementRegistry
对象的引用,可用于注册新的 custom elements,或者获取之前定义过的自定义元素的信息。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Learn Web Components</title>
</head>
<body>
<hello-word text="hello" id="hello-word">
<span slot="context">插槽内容</span>
</hello-word>
<!-- 组件的样式只对 template 内部的标签有效 -->
<template id="hw-template">
<style>
p {
padding: 10px;
background-color: #f40;
color: #fff;
}
</style>
<p>Hello Web Components</p>
<p>
<slot name="context"></slot>
</p>
</template>
<script>
// 所有的组件类必须继承 HTMLElement
class HelloWord extends HTMLElement {
constructor() {
super();
// 得到模板内容
const templateContent = document.querySelector('#hw-template').content;
// 创建一个影子 DOM 节点作为组件的根元素
const shadowRoot = this.attachShadow({ mode: 'open' })
// 将组件节点添加到根元素
shadowRoot.appendChild(templateContent.cloneNode(true))
// 获得组件 text 属性的值
const text = this.getAttribute('text');
shadowRoot.querySelector('p').innerText = text;
}
// 第一次连接文档 DOM 生命周期函数
connectedCallback() {
console.log('第一次被连接到文档 DOM 时被调用');
}
}
customElements.define('hello-word', HelloWord);
</script>
</body>
</html>
从浏览器打开你可以看到
参考
【1】Web Components | MDN
【2】Web Component可以取代你的前端框架吗
【3】深入理解Shadow DOM v1
【4】Web Components零基础实战教学(B站视频)
【5】google polymer 框架