上回说到在完成创建实例,给实例赋值后要创建一个effect,让render函数执行,这样render方法中拿到的数据就会收集这个effect,属性更新时,effect会重新执行,重新再次调用render,完成页面更新。在完成赋值后,会调用setupRenderEffect来完成这件事
第一步
调用setupRenderEffect方法,传入实例进入
setupRenderEffect
- 在这个方法内部,调用effect,传入自己所写的函数
- 函数内部判断当前实例是否被挂载,通过实例上isMounted来判断,如果没有被挂载,那就是初次渲染,我们就去调用render方法,执行的时候传入proxy上下文。
我们先来写h方法
创建h.ts
h方法写法有好几种
- 先判断参数的长度,如果长度等于2,则可能是类型+属性、类型+孩子
- 再判断第二个参数如果不是对象,那一定是孩子
- 如果第二个参数是对象,则去判断第二个参数是不是虚拟节点,通过判断对象上的_v_isVnode变量
- 如果是虚拟节点,调用createVnode,否则就直接创建
- 如果是孩子去调用createVnode
- 再判断参数的长度大于3
- 如果长度等于3并且children是虚拟节点,则用数组包装
- 最后还是调用createVNode
- h方法就要就是兼容h的不同写法
第二步
处理调用render后的返回结果,也就是h的返回结果,subTree,并且这个subTree在实例上也保存一份,实质上也就是个虚拟节点
调用patch方法
用render的返回值继续渲染
patch方法
- 判断虚拟节点中的类型,做对应的处理,用与运算
- 这个时候再调patch跟之前可不同了,这次传入的元素,会走第一个条件,之前是组件,经过一连串处理之后又调回patch
processElement方法
- n1为null,也就是没有初始虚拟节点,表示第一次挂载
mountElement方法
递归渲染
- 先渲染属性
- 然后判断是文本,直接填进去
- 如果是 children,再挂载儿子
mountChildren方法
把孩子循环完之后塞到容器中
normalizeVnode方法
- 如果是对象直接返回
- 如果不是对象,那就要创建一个文本节点
然后我们再重新处理patch中的type
对文本进行特殊处理
processText方法
- 先把文本节点转成元素节点,然后再插入到容器中
- 转成真实元素节点再赋给虚拟dom的el上,把el换成真实节点
如果您觉得有所收获,麻烦动动小手点个攒,谢谢啦~ 预知后事如何,且听下回分解~