Vue3源码系列之组件的渲染流程

351 阅读2分钟

上回说到在完成创建实例,给实例赋值后要创建一个effect,让render函数执行,这样render方法中拿到的数据就会收集这个effect,属性更新时,effect会重新执行,重新再次调用render,完成页面更新。在完成赋值后,会调用setupRenderEffect来完成这件事

第一步

调用setupRenderEffect方法,传入实例进入

setupRenderEffect

Image.png

  • 在这个方法内部,调用effect,传入自己所写的函数
  • 函数内部判断当前实例是否被挂载,通过实例上isMounted来判断,如果没有被挂载,那就是初次渲染,我们就去调用render方法,执行的时候传入proxy上下文。

我们先来写h方法

创建h.ts

h方法写法有好几种

Image.png

Image.png

Image.png

  • 先判断参数的长度,如果长度等于2,则可能是类型+属性、类型+孩子
  • 再判断第二个参数如果不是对象,那一定是孩子
  • 如果第二个参数是对象,则去判断第二个参数是不是虚拟节点,通过判断对象上的_v_isVnode变量
  • 如果是虚拟节点,调用createVnode,否则就直接创建
  • 如果是孩子去调用createVnode
  • 再判断参数的长度大于3
  • 如果长度等于3并且children是虚拟节点,则用数组包装
  • 最后还是调用createVNode
  • h方法就要就是兼容h的不同写法

第二步

处理调用render后的返回结果,也就是h的返回结果,subTree,并且这个subTree在实例上也保存一份,实质上也就是个虚拟节点

Image.png

调用patch方法

Image.png

用render的返回值继续渲染

patch方法

Image.png

  • 判断虚拟节点中的类型,做对应的处理,用与运算
  • 这个时候再调patch跟之前可不同了,这次传入的元素,会走第一个条件,之前是组件,经过一连串处理之后又调回patch

processElement方法

Image.png

  • n1为null,也就是没有初始虚拟节点,表示第一次挂载

mountElement方法

递归渲染

Image.png

Image.png

  • 先渲染属性
  • 然后判断是文本,直接填进去
  • 如果是 children,再挂载儿子

mountChildren方法

Image.png

把孩子循环完之后塞到容器中

normalizeVnode方法

Image.png

  • 如果是对象直接返回
  • 如果不是对象,那就要创建一个文本节点

然后我们再重新处理patch中的type

Image.png

对文本进行特殊处理

processText方法

  • 先把文本节点转成元素节点,然后再插入到容器中
  • 转成真实元素节点再赋给虚拟dom的el上,把el换成真实节点

如果您觉得有所收获,麻烦动动小手点个攒,谢谢啦~ 预知后事如何,且听下回分解~