Web Components
第一章、Web Components 生命周期
Section titled “第一章、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>因为你在父类 BaseComponent 的 connectedCallback 中显式地写了 this.render()。
这是 JavaScript 类继承和多态的标准表现。下面是详细的执行链路:
-
执行顺序拆解
-
当你执行
customElements.define后,浏览器发现页面上有<my-component>标签。 -
浏览器实例化
MyComponent并将其插入 DOM。 -
关键点:触发组件的生命周期钩子
connectedCallback。 -
由于
MyComponent继承自BaseComponent,且自身没有重写connectedCallback,所以它会直接运行父类的该方法。 -
在父类的执行上下文中,
this指向的是当前实例(即MyComponent的实例)。 -
执行到
this.render()时,JS 引擎会寻找当前实例上的render方法,由于子类定义了它,所以成功调用并打印了日志。 -
这里的“模板方法模式”