可能使用到的库stencil(用于生成Web 组件的编译器)

1.shadow DOM

作用:防止内部的样式被外部样式影响

开启shadow Dom显示

Show user agent shadow DOM

基于Web components的库

2.Web Components的未来

作为浏览器自带的API,可以支持在组件内使用前端框架,编译成单独的组件以供使用。

这也就意味着可以在React项目中使用Vue,在无框架应用中使用框架,以及最重要的:使得微前端成为可能,打破了各大框架之间的铁幕

对于未定义的tag,会像一个

一样显示,继承的是HTMLUnknownElement,因为命名规范使得你如果不定义自己的元素并且不符合规范(-分隔),则会继承HTMLUnknownElement

1
<randomElement>111</randomElement>
1
2
document.createElement('randomElement').constructor;
// ƒ HTMLUnknownElement() { [native code] }

使用-分隔,则会继承HTMLElement

1
2
document.createElement('random-element').constructor;
// ƒ HTMLElement() { [native code] }

创建自定义元素

1
2
class Ele extends HTMLElement {}
customElements.define('u-el', Ele)

如果重复定义同一元素控制栏会报错

1
2
3
customElements.define('u-el', Ele)
customElements.define('u-el', Ele)
// Failed to execute 'define' on 'CustomElementRegistry': this name has alreadybeen used with this registry

因为命名是唯一的,因此添加判断逻辑

1
2
3
if (!customElements.get('u-el')) {
customElements.define('u-el', Ele)
}

如果想要继承HTMLButtonElement或者其它已经定义过的元素,需要考虑浏览器的兼容性,只有HTMLElement是几乎所有浏览器都兼容的(除了IE,nmd),但是可以使用polyfills

地址:https://unpkg.com/@webcomponents/custom-elements@1.2.4/custom-elements.min.js

or

使用npm安装

1
npm install @webcomponents/custom-elements

并且定义的新元素需要继承HTMLElement,否则是不合法的

3.Custom Element的生命周期

3.1 connectedCallback

在此周期函数内可以通过this访问当前自定义元素,修改内部元素、自身样式以及添加事件

数据劫持(getters、setters)

3.2 observedAttributesattributeChangedCallback

observedAttributes

用于判断当前触发的attribute是不是需要监控

1
2
3
4
5
6
7
8
9
10
11
12

两者同时使用用于过滤需要监听的元素并监控其变化

```javascript
static get observedAttributes() {
return ['style']
}
attributeChangedCallback(name, oldV, newV) {
if (name === 'style' && oldV !== newV) {
this.style = newV
}
}

属性反射器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static get observedAttributes() {
return ['searchterm', 'data-v', 'checked']
}
attributeChangedCallback(name, oldV, newV) {
console.log(name, oldV, newV);
if (name === 'checked') {
this.checked = newV
}
}

set checked(v) {
const isChecked = Boolean(v)
if (isChecked) {
// 这会触发无限循环
this.setAttribute('checked', '')
} else {
this.removeAttribute('checked')
}
}

以上的写法会触发无限的循环

因此,对此属性添加一个反射器(添加一个setter和getter)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static get observedAttributes() {
return ['checked'];
}
get checked() {
return this.getAttribute('checked');
}
set checked(v) {
this.setAttribute('checked', v);
}
attributeChangedCallback(name, oldval, newval) {
if (name === 'checked') {
// do something
}
}

使用反射器后,当设置checked时,触发setter,设置当前元素的attribute(并不单独设置property),读取这个property也是返回key相同的attribute

对于一个开发者来说,保持attrbutes和properties的一致和同步是十分重要的

attributes的相关函数hasAttribute()getAttribute()setAttribute()

3.3 constructor

constructor与connectedCallback触发时机

注意

1
2
```javascript
document.createElement('u-el')

Element被插入DOM中时connectedCallback才会被触发

初始化属性最好在constructor中,这样比较直观

connectedCallback在现实应用中不怎么使用的一个原因是Shadow DOM

DOM```创建了一个相对独立的小型```DOM```,而```Shadow DOM```可以没有固定的创建时机
1
2
3
4
5
6
7
8
9
10
11
12
13
14

## 3.4 ```disconnectedCallback```
当组件从```DOM```中卸载会被触发,主要用来清除定时器等方法
```javascript
class Ele extends HTMLElement {
connectedCallback() {
this.timer = setInterval(() => {
console.log(11);
}, 1000)
}
disconnectedCallback() {
clearInterval(this.timer)
}
}

3.5 adoptedCallback

当组件在```DOM``中移动后触发

最后更新: 2022年07月16日 13:46