最近看了小崔的mini-vue视频教学,教程很nice,学过后担心忘的太快,故记录一些学习笔记,时时复习,代码已上传github mini-vue
重点内容如下
- effect与reactive的实现
- track 依赖收集 - 记录effect(fn)中的fn
- trigger 触发依赖 - 执行effect(fn)中的fn
- 初始化element
- createApp -> mount -> createVnode -> render -> patch(核心) -> mountComponent -> createComponentInstance -> setupComponent -> setupRenderEffect
- createApp对mount的包装
- mount时创建根元素的vnode,而子节点的vnode会在后面执行render函数时创建
- createVnode,返回一个普通对象vnode,供后续使用
- patch内部判断vnode类型然后进行不同的处理,如果是element节点,直接创建dom节点并插入到container中
- createComponentInstance,返回一个普通对象instance,供后续使用
- setupComponent
- initProps 把props挂载到instance上
- initSlots 把object类型的slots挂载到instance上面,并对每个slot又进行了一层包裹,用于使slot的返回节点是array类型
- setupStatefulComponent 执行setup函数,返回setupState,把render函数挂载到instance上
- setupRenderEffect 执行instance.render,执行时用effect包裹render,收集依赖,同时把this指向instance.proxy,instane.unpdate = runner,获取subTree,subTree也是个vnode,然后递归调用patch,完成整个mount
- 更新element
- 赋值操作触发trigger -> 重新执行effect(render)中的render函数 -> patch(prevTree, subTree)
- 更新普通dom节点
- -> processElement -> patchChildren -> patchKeyedChildren(核心) -> patchProps
- 更新组件
- -> processComponent -> shouldUpdateComponent -> instance.update
- patchKeyedChildren diff算法实现,处理dom移动时使用最大递增子序列算法实现最小移动步数
- shouldUpdateComponent 组件主要判断props是否变化了,props如果变化则手动调用vnode.instance.update方法执行组件的render函数并patch
- 赋值操作触发trigger -> 重新执行effect(render)中的render函数 -> patch(prevTree, subTree)
- template解析
- 解析 <div>hi: {{message}}</div>
- baseParse(template) -> transform(ast) -> generate(ast)
- baseParse
- -> parseChildren(核心) -> parseElement -> parseChildren(递归) -> parseText -> parseInterpolation
- 从左到右处理,处理了一部分就截取一部分,
- parseChildren 执行while循环,退出标志是source.length为0,或者遇到了结束标签,维护一个栈,碰到开始标签入栈,处理完children出栈,chilren处理完了找不到结束标签就提前结束报错
- transform
- 遍历ast(递归),对每个节点执行nodeTransforms中的函数,类似于plugin
- generate
- 遍历ast(递归)生成代码,字符串代码