Skip to content

Web Components

class MyElementLifecycle extends HTMLElement {
// 元素初始化的时候执行
constructor() {
// HTMLElement.prototype.constructor.call(this)
super()
console.log('constructed!')
}
/**
* connectedCallback
* 当元素插入到 DOM 中时,将调用 connectedCallback。
* 这是运行安装代码的好地方,比如获取数据或设置默认属性。
* 可以将其与React的componentDidMount方法进行比较
* vue的mount方法作比较
*/
connectedCallback() {
console.log('connected!')
}
/**
* disconnectedCallback
* 只要从 DOM 中移除元素,就会调用 disconnectedCallback。清理时间到了!
* 我们可以使用 disconnectedCallback 删除事件监听,或取消记时。
* 但是请记住,当用户直接关闭浏览器或浏览器标签时,这个方法将不会被调用。
*
* 可以用window.unload beforeunload或者widow.close 去触发在浏览器关闭是的回调
*
* 可以与 react 中的 componentWillUnmount 的方法进行比较
* vue 中的 destory中是生命周期函数进行对比
*/
disconnectedCallback() {
console.log('disconnected!')
}
// attributeChangedCallback 监听的属性必须定义在 static get observedAttributes() 中
static get observedAttributes() {
return ['my-attr']
}
/**
*
* @param {*} name
* @param {*} oldVal
* @param {*} newVal
*
* 每当添加到observedAttributes数组的属性发生变化时,就会调用这个函数。使用属性的名称、旧值和新值调用该方法
* react 中的 static getDerivedStateFromProps(props, state) 有些类似
* 基本上和vue中的watch使用和observedAttributes + attributeChangedCallback使用雷同;
*/
attributeChangedCallback(name, oldVal, newVal) {
console.log(`Attribute: ${name} changed!`)
}
/**
* 每次将自定义元素移动到新文档时,都会调用 adoptedCallback。只有当您的页面中有 < iframe > 元素时,您才会遇到这个用例。
* 通过调用document.adoptnode (element)调用它,基本上用不上
*/
adoptedCallback() {
console.log('adopted!')
}
/**
* 生命周期的执行顺序 挂载的时候 按照react 或者vue中的执行顺序是相同的
* constructor -> attributeChangedCallback -> connectedCallback
*/
}
// 不是生命周期的API 但是非常重要 注册
window.customElements.define('my-element-lifecycle', MyElementLifecycle)

这里说一个基础知识class原型链的问题

Section titled “这里说一个基础知识class原型链的问题”

这里为什么可以调用render

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<my-component></my-component>
</body>
<script>
class BaseComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = 'this.innerHTML';
this.render();
}
}
class MyComponent extends BaseComponent {
render() {
console.log('加载了render');
}
};
window.customElements.define('my-component', MyComponent);
</script>
</html>

因为你在父类 BaseComponentconnectedCallback 中显式地写了 this.render()

这是 JavaScript 类继承多态的标准表现。下面是详细的执行链路:

  1. 执行顺序拆解

  2. 当你执行 customElements.define 后,浏览器发现页面上有 <my-component> 标签。

  3. 浏览器实例化 MyComponent 并将其插入 DOM。

  4. 关键点:触发组件的生命周期钩子 connectedCallback

  5. 由于 MyComponent 继承自 BaseComponent,且自身没有重写 connectedCallback,所以它会直接运行父类的该方法。

  6. 在父类的执行上下文中,this 指向的是当前实例(即 MyComponent 的实例)。

  7. 执行到 this.render() 时,JS 引擎会寻找当前实例上的 render 方法,由于子类定义了它,所以成功调用并打印了日志。

  8. 这里的“模板方法模式”