【手写 Vue2.x 源码】第四十篇 - 组件部分 - 组件的生命周期
创始人
2024-05-16 03:04:54
0

一,前言

上篇,介绍了组件部分-组件的编译,主要涉及以下几部分:

  • 组件编译流程介绍:html->render->vnode
  • 创建组件虚拟节点:createComponent

本篇,组件部分-组件的生命周期;


二,前文回顾

  1. Vue.component 方法:
  • Vue.component 方法用于注册 Vue 全局组件;
  • 当组件定义 definition 为对象时,在Vue.component内部会使用Vue.extend方法对组件定义 definition 进行处理,返回组件的构造函数;
  • 将组件与组件的构造函数关系维护到全局对象Vue.options.components中,便于后续的使用;
  1. 当 new Vue 初始化时:
  • new Vue 会执行 Vue 原型方法 _init 进行初始化流程,mergeOptions 会进行组件的合并;
  • 通过mergeOptions(vm.constructor.options, options)将全局组件定义合并到局部组件定义上;
  • 组件查找时,会优先查找对应的局部组件定义,若未找到再通过链__proto__继续向上查找全局组件定义;
  1. 组件的编译流程:
  • 与模板编译流程一致,html 模板->AST语法树->生成 render 函数,执行_c(即 createElement)创建虚拟节点;
  • 在 createElement 方法中,如果是组件则通过 createComponent 方法创建组件虚拟节点componentVnode;
  • 在 createComponent 方法中,当 Ctor 为对象时,使用 Vue.extend 进行处理,生成组件的构造函数;
  • componentVnode 中包含 componentOptions 组件选项,componentOptions 中包含组件构造函数 Ctor(此时 componentOptions 中的 Ctor 一定为函数);

到这里,就完成了组件虚拟节点的创建;

注意:所有的组件都是通过 Vue.extend 方法来实现的;

接下来,根据组件的虚拟节点创建组件的真实节点,之后再进行挂载;

todo 又读了一遍,感觉写的还不好, 先做标记:
1,全局组件注册:包含 Vue.component 和 extend 两部分
...
后续仍需改善

三,组件的生命周期

当组件初始化时,执行初始化的回调,即hook钩子;在不同的地方执行不同的钩子

new Ctor()

扩展组件 data 属性,为组件添加生命周期钩子函数:

/*** 创造组件的虚拟节点 componentVnode*/
function createComponent(vm, tag, data, children, key, Ctor) {if(isObject(Ctor)){// 获取 Vue 并通过 Vue.extend 将对象处理成为组件的构造函数Ctor = vm.$options._base.extend(Ctor)}// 扩展组件的生命周期data.hook = {init(){let child = new Ctor({});child.$mount();},prepatch(){},postpatch(){}}// 创建vnode时,组件是没有文本的,需要传入 undefined// 注意:组件没有孩子,组件的孩子就是插槽,将 children 放到组件的选项中let componentVnode = vnode(vm, tag, data, undefined, key, undefined, {Ctor, children, tag});return componentVnode;
}

4,创建组件的真实节点

如何去找组件的真实节点?

create 方法完成之后,会继续执行 patch 方法,

createElm 方法,是真正将虚拟节点转化为真实节点的位置;

由于组件的加入,此时的 createElm 方法中可能会包含 componentOptions:

第一次:id 为 app 的真实节点

01.png

第二次:my-button 组件

02.png

在原 createElm 方法中,是直接通过document.createElement(tag)创建标签,现在还需要添加对组件类型的处理,通过createComponent创建组件的真实节点:

/*** 创造组件的真实节点* @param {*} vnode */
function createComponent(vnode) {console.log(vnode)
}// 面试:虚拟节点的实现?如何将虚拟节点渲染成真实节点
export function createElm(vnode) {// 虚拟节点必备的三个:标签,数据,孩子let { tag, data, children, text, vm } = vnode;debugger;// vnode.el:绑定真实节点与虚拟节点的映射关系,便于后续的节点更新操作if (typeof tag === 'string') { // 元素// 组件的处理if(createComponent(vnode)){ // 将组件的虚拟节点,创建成为组件的真实节点}// 处理当前元素节点vnode.el = document.createElement(tag) // 创建元素的真实节点updateProperties(vnode, data)  // 处理元素的 data 属性// 处理当前元素节点的儿子:递归创建儿子的真实节点,并添加到对应的父亲中children.forEach(child => { // 若不存在儿子,children为空数组vnode.el.appendChild(createElm(child))});} else { // 文本:文本中 tag 是 undefinedvnode.el = document.createTextNode(text)  // 创建文本的真实节点}return vnode.el;
}

在 createComponent 方法中,在 data 属性上进行组件生命周期的扩展:

// src/vdom/index.jsfunction createComponent(vm, tag, data, children, key, Ctor) {if(isObject(Ctor)){// 获取 Vue 并通过 Vue.extend 将对象处理成为组件的构造函数Ctor = vm.$options._base.extend(Ctor)}// 扩展组件的生命周期data.hook = {init(){},prepatch(){},postpatch(){}}// 创建vnode时,组件是没有文本的,需要传入 undefined// 注意:组件没有孩子,组件的孩子就是插槽,将 children 放到组件的选项中let componentVnode = vnode(vm, tag, data, undefined, key, undefined, {Ctor, children, tag});return componentVnode;
}

在 createComponent 方法中,尝试获取生命周期 hook,如果 hook 存在说明是组件,再拿到 init 方法,处理虚拟节点 vnode:

/*** 创造组件的真实节点* @param {*} vnode */
function createComponent(vnode) {console.log(vnode);let i = vnode.data;if((i = i.hook)&&(i = i.init)){ // 最后 i 为 init 方法i(vnode); // 将 vnode 传入 init 方法}
}
先把 hook 赋值给 i,再把 init 赋值给 i,
最终 i 为 init 方法;

组件的初始化,即 new 组件的构造函数,此时就会进入 init 方法:

todo


4,创建组件的真实节点

通过 new Ctor 拿到组件的实例,并调用组件的 $mount 方法,生成一个 $el;
vnode.componentInstance = new Ctor()
vnode.componentInstance.$el即为组件渲染后的结果;

5,将组件的 vnode.componentInstance.$el插入到父标签中

6,当组件实例化 new Ctor() 时,会进行组件的初始化,此时会为组件添加一个独立的渲染过程,为每个组件生成各自的渲染 watcher;当组件更新时,只需要更新自己组件对应的渲染 watcher 即可;所以性能是非常高的,因为在组件渲染时,组件对应的属性会收集自己的渲染 watcher


四,结尾

本篇,介绍了组件部分-组件的生命周期,主要涉及以下几部分:

todo

下一篇,组件部分-生成组件的真实节点

今天公司值班没有网络,先怼上明天周末再修改,见谅~
备注:今天更新了一小部分,这篇还有太多问题,明天继续搞定,见谅~


维护日志

  • 20210814:
  • 优化了“前文回顾”部分,总结前置知识点,能够更平滑过渡到当前内容;

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...