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

news2024/11/15 11:10:04

一,前言

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

  • 组件编译流程介绍: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 是 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 方法:

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:
  • 优化了“前文回顾”部分,总结前置知识点,能够更平滑过渡到当前内容;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176437.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

logstash + logback实现分布式日志采集

😊 作者: 一恍过去💖 主页: https://blog.csdn.net/zhuocailing3390🎊 社区: Java技术栈交流🎉 主题: logstash logback实现分布式日志采集⏱️ 创作时间: 2023年1…

Logback基本使用

文章目录Logback的使用1. logback入门2. logback 配置3. logback-access的使用Logback的使用 Logback是由log4j创始人设计的另一个开源日志组件,性能比log4j要好官方网站:https://logback.qos.ch/index.htmlLogback主要分为三个模块: logbac…

基于高通平台的dToF Sensor开机点亮教程

作为一个优秀的驱动工程师,迅速点亮目前市面上的Soc平台是非常必须的。如果你花费了很多时间无法Set up起平台,那你这驱动开发可能还有待提升,特别如今这市场,想要更高更强,驱动开发变得吃香了。一般圈子里的朋友,驱动开发都是大杀四方,比如高通平台,全志平台,MTK平台…

【Python】司徒卢威函数

文章目录简介图像其他相关函数简介 最开始看到这个名字,我也很激动,终于有个中文姓氏的数学公式了,然鹅司徒卢威是个俄国人,而且司徒卢威完全是音译,就离谱。 司徒卢威函数是下面的非齐次贝赛尔方程的一组解&#xf…

2022年,经历了两段实习后,我学会了……

前言: 大家好,我是小威。借着csdn的这个活动,我也来对自己的2022做一个回顾,同时对2023做一个合理的规划,希望我的经历也能对诸佬们带来绵薄之力。 感谢诸位大佬对小威这年的支持,祝诸佬们新年快乐哟~&…

Unix\Linux多线程复健

线程是程序中完成一个独立任务的完整执行序列(是一个可调度的实体) 一个进程可以包含多个线程 查看指定进程的线程号: ps -Lf pid 进程是CPU分配资源的最小单位,线程是操作系统调度执行的最小单位 分类: 内核线程:切换由内核控制&…

代码随想录--字符串习题总结

代码随想录–字符串习题总结 1.LeetCode344 反转字符串 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 1&…

Spring AOP 详解

Spring AOP 详解一、什么是 Spring AOP二、为何要用 AOP三、Spring AOP3.1 AOP 组成3.1.1 切面 (Aspect)3.1.2 连接点 (Join Point)3.1.3 切点 (Pointcut)3.1.4 通知 / 增强方法 (Advice)3.1.5 小结3.2 Spring AOP 使用3.2.1 添加 AOP 框架支持3.2.2 定义切面和切点3.2.3 定义相…

Python---字典相关知识

专栏:python 个人主页:HaiFan. 专栏简介:本专栏主要更新一些python的基础知识,也会实现一些小游戏和通讯录,学时管理系统之类的,有兴趣的朋友可以关注一下。 字典思维导图字典是什么创建字典查找键key字典的…

十分钟入门Zigbee

大部分教程通常都是已Zigbee原理开始讲解和学习,各种概念让初学者难以理解。本教程从一个小白的角度出发,入门无需任何Zigbee底层原理知识,只需要基本的MCU研发经验就可以掌握,让您快速实现zigbee组网和节点之间通信。 本教程采用…

JDBC快速入门,如何使用JDBC操作数据库?

文章目录1. 前言2. JDBC 概述2.1 概念2.2 优点3. JDBC 快速入门Java编程基础教程系列1. 前言 在 Java 开发中,使用 Java 语言操作数据库是非常重要的一部分,那么 Java 语言是如何操作数据库的呢?我们需要使用不同厂商的数据库时,…

23种设计模式(二十二)——访问者模式【行为变化】

文章目录 意图什么时候使用访问者真实世界类比访问者模式的实现访问者模式的优缺点亦称:Visitor 意图 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于其内部各个元素的新操作。 什么时候使用访问者 1、如果你需要对一个复杂对象…

Redis脑裂为何会导致数据丢失?

1 案例 主从集群有1个主库、5个从库和3个哨兵实例,突然发现客户端发送的一些数据丢了,直接影响业务层数据可靠性。 最终排查发现是主从集群中的脑裂问题导致:主从集群中,同时有两个主节点都能接收写请求。 影响 客户端不知道应…

Python数模笔记-模拟退火算法(5)求解旅行商问题的联合算子模拟退火算法

Python数模笔记—求解旅行商问题的联合算子模拟退火算法(完整例程) 文章目录Python数模笔记—求解旅行商问题的联合算子模拟退火算法(完整例程)0 摘要1 引言2 模拟退火算法求解旅行商问题2.1 模拟退火算法2.2 多个新解的竞争机制2…

详解P431 塔防

题目说明gsy 最近在玩一个塔防游戏,但是这次她控制的是迷宫中的怪兽而非防御塔建造者游戏的地图是一个 n * m 的矩阵,起点在 (1,1) ,终点在 (n,m) ,gsy 每次可以选择上下左右四个方向移动 1 步这个地图上有很多的防御塔&#xff0…

“华为杯”研究生数学建模竞赛2005年-【华为杯】B题:空中加油问题的讨论(附获奖论文及C++代码)

赛题描述 对飞行中的飞机进行空中加油,可以大大提高飞机的直航能力。为了简化问题,便于讨论,我们作如下假设。 少辅机架数两种情况给出你的作战方案。 论文 一. 问题重述 空中加油技术可以大大提高飞机的直航能力。作战飞机称为主机,加油机称 为辅机。已知:( 1 )主…

[创业之路-50] :动态股权机制 -5- 创业公司股权分配常见的坑

1、 分工不清晰,决策不清晰,理念不一致分工必须要简单明晰初创公司的合伙人一般是三到五个,最合理的架构一开始最好是三个人,相互之间需要一段时间的磨合,了解清楚各自的特长,工作经历等等,不要…

微信小程序开发uni-app

一、uni-app简介官网:https://uniapp.dcloud.io/PC端;移动端:(APP,WebApp);纯原生:(IOS,Android ) 应用商店;H5Hybrid 模式(混合&…

活动星投票最美农商人网络评选微信的投票方式线上免费投票

“最美农商人”网络评选投票_视频投票的相关评选_投票统计_微信不记名免费评选投票用户在使用微信投票的时候,需要功能齐全,又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便,用户可以随时使用手机微信小程序获得线上投票服务…

树莓派Python虚拟环境、PyQt5、PySide2

要从头设置好一台可用于开发的树莓派,可以参考树莓派 4B 无屏幕,连接WiFi、SSH、VNC,系统换源、pip换源,安装中文输入法 Python虚拟环境 树莓派(或者说arm平台)使用Python虚拟环境的正确方式是使用pipenv…