写点什么

【Vue2.x 源码学习】第四十篇 - 组件部分 - 组件的生命周期

用户头像
Brave
关注
发布于: 2 小时前
【Vue2.x 源码学习】第四十篇 - 组件部分 - 组件的生命周期

一,前言


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


  • 组件编译流程介绍: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 的真实节点:


第二次:my-button 组件:


在原 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 是 undefined vnode.el = document.createTextNode(text) // 创建文本的真实节点 } return vnode.el;}
复制代码


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


// src/vdom/index.js
function 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 方法;


4,创建组件的真实节点


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


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


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


四,结尾


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

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

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vue2.x 源码学习】第四十篇 - 组件部分 - 组件的生命周期