vue组件渲染流程源码分析

组件渲染源码分析

组件渲染主要分为分为两步, 一是创建组件对应的虚拟dom 二是将组件所生成的真实dom插入到父组件的组件标签所对应的位置

    1. 创建组件对应的虚拟dom
      1. vue内部会先生成一个render函数, 执行render函数就会生成虚拟dom, 所以创建组件虚拟dom这一步发生在render函数里面的_c
      1. render函数, 实际上是通过ast转换成特定格式的字符串, 再将字符串插入到new Function() { with(this); 字符串 }这种方式来实现生成一个render函数的(具体实现过程可以去看我关于vue源码解读的文章), render函数内部通过调用_c 转换成虚拟dom的
      1. _c方法接收一个对象, 对象里面包含tag data childern这些属性, tag就是当前标签的名称(比如div就是tag的值, my-component这个也是tag的值), data就是定义在组件标签身上的属性(父传给子的属性, 子发出的方法都在这个data里面), childern就是当前标签内部的子标签对象
      1. _c方法执行时, 会拿到这个tag值, 判断这个tag值是不是html定义的那些标签, 如果是就表示是一个普通标签, 就去调用生成普通虚拟dom的方法, 如果不是,就证明这是一个组件标签, 那就进入生成组件虚拟dom的方法
      1. 生成组件虚拟dom方法, 这个方法内部会先创建一个对象, 这个对象就是虚拟dom, 接着向对象身上增加data属性, data是一个对象, data中有一个hooks属性, 这个hooks属性是一个对象, 里面包含两个方法, 一个是init方法, 另一个是prepatch方法(prepatch方法主要在组件props变化的时候调用, 后续有时间的话, 会再写一篇组件更新对比的文章), init方法主要就是用来进行组件初始化操作的
      1. init方法内部会拿到组件所对应的Ctor构造函数, 接着创建组件实例, 执行mount方法(这块不需要先懂为什么这样做,等到组件虚拟dom转真实dom时,我会再重新对这块再说一下,现在只需要有个印象就行),做三件事,1获取到组件构造函数2创建组件实例3执行组件实例的mount方法(这块不需要先懂为什么这样做, 等到组件虚拟dom转真实dom时, 我会再重新对这块再说一下, 现在只需要有个印象就行), 做三件事, 1获取到组件构造函数 2创建组件实例 3执行组件实例的mount方法(这块不需要先懂为什么这样做,等到组件虚拟dom转真实dom,我会再重新对这块再说一下,现在只需要有个印象就行),做三件事,1获取到组件构造函数2创建组件实例3执行组件实例的mount方法(注意: $mount() 什么都没有传入, 这块很重要)
      1. init方法添加完之后, 就会执行Vue.extend方法, Vue.extend方法需要传入当前的组件所对应的配置对象, 也就是new Vue中传入的对象的components的my-component属性所对应的value, Vue.extend方法拿到配置对象之后, 会将全局Vue.options和配置对象进行合并, 合并之后会作为Vue.extend返回的构造函数Sub.options的值(这块不懂的看我关于Vue.extend源码分析的文章), 所以这块执行Vue.extend返回一个构造函数, 将这个构造函数添加到组件的虚拟dom对象身上, 属性名为Ctor
      1. 这里还会将参数data(这里data指的是调用生成组件虚拟dom方法传过来的data, 也就是组件标签身上的属性)进行剥离,
        如果在组件的配置对象身上的props定义的有data中的属性, 就将data中的这个属性取出来添加到props变量身上, 还有事件也会处理(这里不一一说, 这篇主要是理解组件渲染流程), 剥离完之后, data就只剩下没有定义的在props身上的了, data就会作为组件虚拟dom的attrs属性(这个也就是组件内部$attrs的一个由来), props作为组件虚拟dom的props属性值
      1. 组件虚拟dom创建完毕, 重点两件事情 1创建出组件构造函数 2向组件虚拟dom对象身上增加init钩子函数
    1. 将组件所生成的真实dom插入到父组件的组件标签所对应的位置
      这个过程会比较长, 比较绕, 我先大概解释一下, vue解析到组件所对应的虚拟dom时, 就会去调用组件的init方法, 组件init方法内部会创建组件实例, 组件构造函数中的_init方法执行, _init方法执行完成之后, 实例执行$mount方法, $mount方法中因为没有传参数会将组件的虚拟dom(也就是将组件template转换成的虚拟dom)转换成真实的dom, 真实dom作为组件的el属性, 之后组件方法执行完毕, 返回生成组件标签真实节点的地方, 判断组件实例身上有el属性的话, 就会将组件的el属性作为当前组件标签所对应的真实dom, 插入到vue实例生成的真实dom里面, 真实dom挂载到页面上, 组件渲染完成
      1. 虚拟dom全部创建完成之后, 就会将虚拟dom转换成真实dom, 虚拟dom转真实dom这一步发生在_update方法中
      1. _update方法内部会判断是否有上一次生成的虚拟dom(通过prevnode值判断, 具体名称不记得了), 如果没有就证明这是第一次渲染就进入createElement方法中执行
      1. createElement方法, 拿到虚拟dom, 生成最外层的真实dom, 之后遍历虚拟dom的childern每一项, 继续调用createElement, 生成之后的真实元素, 插入到上一级的真实dom里面(这里指的就是最外层了), createElement执行, 遇到了组件虚拟dom
      1. createElement方法遇到组件虚拟dom, 会判断当前虚拟dom身上是否有data属性, data中是否有hooks, hooks中是否有init方法, 有就去执行init方法(注意这里会跳到组件虚拟dom的init方法中, 会在init中执行很多方法, 一会执行完都要回到这里), init方法执行之后, 回到这里, 继续执行看当前组件虚拟dom所对应的组件实例身上是否有el属性, 如果有就将el作为当前组件标签的真实节点, 插入到上一级的真实dom里面
      1. init方法, 现在回到了的组件虚拟dom的init方法中, 这里就会拿到组件的构造函数, 然后创建实例, 将这个实例添加到组件虚拟dom对象身上, 实例创建就会执行构造函数的_init方法, 构造函数的_init方法中会传入一个对象, 对象中有_isComponent: true, 组件虚拟dom身上的props attrs都会放在这个对象身上,
      1. 执行_init方法, _init方法会判断_isComponent如果为true, 就会vm.options = Object.create(vm.constructor.options), 也就是说会创建一个对象, 这个对象的原型指向其构造函数的options(构造函数的options会将全局Vue.options与当前配置对象进行合并), 这个对象身上找不到属性时, 就会去原型身上查找(这里有面试题, 为什么data必须是一个函数, 我后续会再专门针对这个问题讲一下), _init方法执行完毕
      1. 执行$mount方法, 注意这里什么参数都没有传进去, mount方法主要就是将template转换成render函数,创建一个watcher执行vm.update(vm.render())(不了解的话,跳过我的这句话,就认为mount方法主要就是将template转换成render函数, 创建一个watcher执行vm._update(vm.render())(不了解的话, 跳过我的这句话, 就认为mount方法主要就是将template转换成render函数,创建一个watcher执行vm.update(vm.render())(不了解的话,跳过我的这句话,就认为mount会将虚拟dom转成真实dom就好了),
        组件虚拟dom生成之后, 执行组件的_update方法
      1. 组件的_update方法执行, _update根据prevnode判断是不是第一次渲染, 是第一次渲染就去执行组件的createElement方法
      1. 组件的createElement方法执行, 会接收$mount传过来的值, 如果接收过来的是undefined就是没有传的, vue就会将组件的虚拟dom转成真实dom, 然后放到组件的el属性身上
      1. 组件init方法执行完成, 会到init构造函数调用那里, 拿到组件的el属性之后, 就将其作为组件标签所对应的真实dom, 再将这个真实dom插入到父级真实dom里面
        到此为止, 组件渲染流程完毕(上述有些地方可能与源码中并不一一吻合, 但上述就是vue渲染组件的一个整体源码流程)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值