Web Component
作为开发者,我们都知道尽可能多的重用代码是一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的HTML(以及相关的样式和脚本),有时您不得不写代码来呈现自定义UI控件,并且如果您不小心的话,多次使用它们会使您的页面变得一团糟。
Web Components旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。
- Custom elements(自定义元素): 一组javaScript API,允许定义custom elements以及行为。
- Shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
- HTML templates(HTML模板):====和 ====元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
实现web component的基本方法:
- 创建一个类或函数来指定web组件的功能,如果使用类,请使用 ECMAScript 2015 的类语法(参阅类获取更多信息)。
- 使用
CustomElementRegistry.define()
方法注册您的新自定义元素 ,并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。 - 如果需要的话,使用
Element.attachShadow()
方法将一个shadow DOM附加到自定义元素上。使用通常的DOM方法向shadow DOM中添加子元素、事件监听器等等。 - 如果需要的话,使用
](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/template) 和[
和`` 定义一个HTML模板。再次使用常规DOM方法克隆模板并将其附加到您的shadow DOM中。 - 在页面任何您喜欢的位置使用自定义元素,就像使用常规HTML元素那样。
一、自定义元素
custom elements(自定义标签)
CustomElementRegistry 接口的实例用来处理 web 文档中的 custom elements — 该对象允许你注册一个 custom element,返回已注册 custom elements 的信息,等等。
CustomElementRegistry.define() 方法用来注册一个 custom elemen(自定义组件)
customElements.define('word-count', WordCount, { extends: 'p' });
- 参数一:自定义的标签名字,中间必须有短线
- 参数二:用于定义元素行为的类
- 参数三(可选):指定继承哪个内置元素。(任何的)
class WordCount extends HTMLParagraphElement {
constructor() {
// 必须首先调用 super 方法
super();
// 元素的功能代码写在这里
// 1. 创建一个 shadow root ,mode值 open/closed,隐藏元素
var shadow = this.attachShadow({mode: 'closed'});
// 2.创建元素节点,并设置类名
var wrapper = document.createElement('span');
wrapper.setAttribute('class','wrapper');
var info = document.createElement('span');
info.setAttribute('class','info');
// 3.设置属性,定义在customDom上面的属性
var text = this.getAttribute('text');
info.textContent = text;
// 4.创建css样式
var style = document.createElement('style');
style.textContent = ``;
// 5.将创建的元素附加到 shadow dom
shadow.appendChild(style);
shadow.appendChild(wrapper);
wrapper.appendChild(info);
...
}
}
// 注册自定义组件
window.customElements.define("custom-elem",WordCount);
constructor()函数里面可以设定一些生命周期的回调函数,特定时间,回调函数自动被调用
connectedCallback() : 元素首次被插入到文档DOM节点上时被调用。
attributeChangedCallback() : 元素增加、删除或者修改某个属性时被调用。
二、Shadow DOM(隐藏元素)
作用:用于封装组件元素的内部细节,向外提供属性注入,可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。可以将一个隐藏的、独立的 DOM 附加到一个元素上
相关术语:
- Shadow host:一个常规 DOM节点,Shadow DOM 会被附加到这个节点上。
- Shadow tree:Shadow DOM内部的DOM树。
- Shadow boundary:Shadow DOM结束的地方,也是常规 DOM开始的地方。
- Shadow root: Shadow tree的根节点。
用法
Element.attachShadow()方法创建一个 shadow root,将创建的元素附加到 shadow dom,
有一个mode属性,值可以为open或者closed;
let shadow = elementRef.attachShadow({mode: 'open'});
let shadow = elementRef.attachShadow({mode: 'closed'});
-
open
表示可以通过页面内的 JavaScript 方法来获取 Shadow DOMlet myShadowDom = myCustomElem.shadowRoot;
-
closed表示不可以从外部获取 Shadow DOM 了——
myCustomElem.shadowRoot
将会返回null
三、使用模板(Templates)
当必须在网页上重复使用相同的标记结构时,可以使用模板(template),使用HTML 的====元素实现,此元素及其内容不会在DOM中呈现,但仍可使用JavaScript去引用它。
定义一个template: (此代码在html中插入,但不会显示在页面当中,只有通过js引用的时候才会显示)
<template id="my-template">
<style>
p {
color: white;
background-color: #666;
padding: 5px;
}
</style>
<p>My Template</p>
</template>
通过js引用到dom中:
let template = document.getElementById('my-template');
let templateContent = template.content;
document.body.appendChild(templateContent);
*与 web Component一起使用: (模板与自定义组件的结合)
customElements.define('my-template',
class extends HTMLElement {
constructor() {
super();
let template = document.getElementById('my-paragraph');
let templateContent = template.content;
const shadowRoot = this.attachShadow({mode: 'open'})
.appendChild(templateContent.cloneNode(true));
// templateContent.cloneNode(true)将模板拷贝到shadowRoot的根结点上
}
})
使用插槽:(在模板中定义插槽的位置,然后在自定义标签中指定slot的属性值,可以继承插槽所在的标签样式以及内容)
<!-- 使用模板 -->
<text-template>
<!-- 使用插槽 -->
<span slot="my-text"></span>
</text-template>
<!-- 定义模板 -->
<template id="my-template">
<style type="text/css">
p {
color: blueviolet;
font-size: 16px;
padding: 5px;
}
</style>
<p>
<slot name="my-text">My default text</slot>
hhhhh
</p>
</template>
> 相关链接:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components