前言
组件是前端的发展方向,现在流行的 React 和 Vue 都是组件框架。
谷歌公司由于掌握了 Chrome 浏览器,一直在推动浏览器的原生组件,即 Web Components API。相比第三方框架,原生组件简单直接,符合直觉,不用加载任何外部模块,代码量小。目前,它还在不断发展,但已经可用于生产环境。
怎么说呢,无意中就发现了这个东西,感觉很有意思,打算学习研究一下。
参考:
- Web Components 入门实例教程
- Web Components 官方文档
- 面向未来的原生 Web Components UI组件库 ,这个老哥比较牛叉,直接用
Web Components
写了个组件库
自定义元素
自定义元素比如:<user-card></user-card>
,这种自定义的 HTML 标签,称为自定义元素(custom element)。根据规范,自定义元素的名称必须包含连词线,用与区别原生的 HTML 元素。
组件示例
组件user-card.js
:
const template = document.createElement('template');
template.innerHTML = `
<style>
h2 {
border:1px solid red;
}
</style>
<h2>
<span>Hello World</span>
</h2>
`;
class UserCard extends HTMLElement {
constructor() {
super()
let shadow = this.attachShadow({
mode: 'closed' });
shadow.appendChild(template.content.cloneNode(true));
}
}
window.customElements.define('user-card', UserCard);
使用test.vue
:
<template>
<div>
<user-card id="test"></user-card>
</div>
</template>
<script setup lang="ts">
import './components/user-card.js';
</script>
<style scoped lang="scss">
</style>
customElements.define()
自定义元素需要使用 JavaScript 定义一个类,所有<user-card>
都会是这个类的实例。
浏览器原生的customElements.define()
方法,告诉浏览器<user-card>
元素与这个类关联。
语法
customElements.define(name, constructor, options);
name:自定义元素名
constructor:自定义元素构造器
options:控制元素如何定义. 目前有一个选项支持,extends. 指定继承的已创建的元素. 被用于创建自定义元素.
template和slot
使用 <template>
和 <slot>
元素创建一个可以用来灵活填充 Web组件的 shadow DOM 的模板。
这里不介绍,根vue中的模板和插槽没什么区别,具体内容见:使用 templates and slots
attachShadow
语法
var shadowroot = element.attachShadow(shadowRootInit);
用来指定模式,官网的说明是:attachShadow
class UserCard extends HTMLElement {
constructor() {
super()
let shadow = this.attachShadow({
mode: 'open' });
shadow.appendChild(template.content.cloneNode(true));
}
connectedCallback() {
console.log("添加到页面")
this.updateStyle(this);
}
updateStyle(elem) {
//获取根节点
let shadowRoot = elem.shadowRoot
// open时可以获取到,closed时为null
console.log("根节点:", shadowRoot)
}
}
shadow DOM
Web components 的一个重要属性是封装——可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。其中,Shadow DOM 接口是关键所在,它可以将一个隐藏的、独立的 DOM 附加到一个元素上。本篇文章将会介绍 Shadow DOM 的基础使用。
Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中——它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。
有一些 Shadow DOM 特有的术语需要我们了解:
- Shadow host:一个常规 DOM节点,Shadow DOM 会被附加到这个节点上。
- Shadow tree:Shadow DOM内部的DOM树。
- Shadow boundary:Shadow DOM结束的地方,也是常规 DOM开始的地方。
- Shadow root: Shadow tree的根节点。
设置样式:
- 方式一:最开始的那个例子的格式
- 方式二:
var style = document.createElement('style');
style.textContent = `
.wrapper {
position: relative;
}
....
`
shadow.appendChild(style);
- 方式三:加载外部样式
const linkElem = document.createElement('link');
linkElem.setAttribute('rel', 'stylesheet');
linkElem.setAttribute('href', 'style.css');
// 将所创建的元素添加到 Shadow DOM 上
shadow.appendChild(linkElem);
推荐使用前两种方式, 因为<link>
元素不会打断 shadow root 的绘制, 因此在加载样式表时可能会出现未添加样式内容,导致闪烁。
生命周期
定义在自定义元素的类定义中的特殊回调函数,影响其行为:
- connectedCallback: 当自定义元素第一次被连接到文档DOM时被调用。
- disconnectedCallback: 当自定义元素与文档DOM断开连接时被调用。
- adoptedCallback: 当自定义元素被移动到新文档时被调用。
- attributeChangedCallback: 当自定义元素的一个属性被增加、移除或更改时被调用。