Vue3源码系列之组件的创建流程

212 阅读3分钟

第一步

 用位运算来给虚拟节点加类型,我们先创建ShapeFlag.ts文件

Image.png

第二步

创建vnode.ts文件写createVNode方法

Image.png

  • 创建一个对象来描述内容,上面的shapeFlag就是我们通过判断type来给虚拟节点增加类型,之后通过&运算我们就知道虚拟节点的类型是什么

然后我们需要对儿子的类型做出判断

Image.png

Image.png

  • 用虚拟节点自己的类型和儿子的类型做或运算,这样就可以用虚拟节点上的shapeFlag判断出自己当前的类型和儿子的类型

第三步

然后我们回到renderer.ts中去写render方法了,对这个地方没印象的同学可以回到上篇文章去看下

Image.png

render调用patch方法

Image.png

  • 第一个参数是之前的虚拟节点,初始调用给个null,第二个参数是当前要渲染的虚拟节点,第二个参数是渲染到的容器

patch方法

Image.png

  • 判断虚拟节点中的类型,做对应的处理,用与运算

然后调用processComponent去处理组件,将三个参数传入

Image.png

processComponent方法

然后判断n1是否存在,如果没有上一次的虚拟节点我们就将n2,也就是新虚拟节点挂载到容器里,调用mountComponent方法

Image.png

mountComponent方法

Image.png

createComponentInstance方法

我们继续去写createComponentInstance方法去创建实例

Image.png

  • 主要做的事情就是初始化

setupComponent方法

将数据解析到实例上,给实例赋值

Image.png

  • 从vnode中解析出props和attrs,将它们放到实例上
  • 检查当前是不是有状态的组件,通过当前的vnode中shapeFlag,与shapeFlag事先写好的标识组件有状态进行与操作
  • 如果当前组件有状态,就调用当前实例的setup方法,用setup的返回值填充

setupStatefulComponent方法

Image.png

  • 获取当前组件的类型,拿到setup方法
  • 执行setup方法
  • 然后调用组件上的render方法
  • instance中的props、attrs、slots、emit、expose会被单独提取出来,因为实际开发中可能会被用到

createSetupContext方法

创建setup的第二个参数,将实例中包含的内容,提取一些传递给context

Image.png

代理

Image.png

我们希望当我们访问这个实例上的某个属性,能走我们自己的get方法

现在我们去写这个handlers

PublicInstanceProxyHandlers

Image.png

  • 当我们去访问代理对象proxy中的属性的时候,会分别在setupState、props、data中去寻找,如果找不到就返回undefined
  • 设置值也是如此
  • 这样写的好处是取值非常方便 然后我们去判断setup是否有,有去执行,没有就完成组件的启动

Image.png

finishComponentSetup方法

Image.png

处理setup执行的返回值

Image.png

handleSetupResult方法

Image.png

  • 判断setup执行返回的结果是否是函数,如果是函数,则赋值给实例的render上
  • 判断如果是对象则赋值到setupState上,对这个变量还有印象吧,上下文proxy上查找中会第一个从这里面查找
  • 最后调用finishComponentSetup方法

最后总结一下组件的创建流程

  • 先创建实例
  • 然后把需要的数据解析到实例上,也就是给实例赋值,比如state、props、attrs、render等
  • 最后创建一个effect,让render函数执行,这样render方法中拿到的数据就会收集这个effect,属性更新时,effect会重新执行

本篇博文只写了前两步,最后一步,我们下篇博文再实现

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