前言
怎么快怎么来,你们的时间都宝贵,用最短的时间学到最多的知识。
咱们能够将petite-vue
理解为:用真实DOM
取代Vue
模版的简易Vue
。html
好比以下Demo
:vue
<script type="module"> import { createApp } from '../src' createApp({count: 0}).mount() </script> <div v-scope> <button @click="count++">add 1</button> <p>{{count}}</p> </div> 复制代码
div
及其子孙节点是真实的DOM
标签,因此页面初始化时以下:node
接着执行以下代码,完成petite-vue
初始化:react
createApp({count: 0}).mount() 复制代码
此时页面:git
读框架源码切忌一上手就从入口函数一路调试,很容易就懵逼了。正确的方式是像剥洋葱同样一层一层剥开:github
因此,让咱们先从Performance
面板看看首屏渲染的调用栈:框架
调用栈大致分为蓝框、红框两部分,先看左边蓝框部分:函数
经过createContext
与reactive
关键词判断大概是建立响应式上下文
。至于响应式
的含义,咱们还不清楚。post
接着看右边红框部分:url
从调用栈深度、页面渲染的效果咱们猜想,这部分作的工做包括:
-
遍历
DOM
-
完成数据与视图的双向绑定
-
初始化渲染
接下来,咱们来验证猜测。
注意,到目前为止,咱们一行源码都还没看
验证遍历DOM
调用栈中walk
与walkChildren
被调用屡次,大几率他们就是具体遍历工做执行的方法,让咱们确认下。
在源码walk
方法中打上log
:
export const walk = (node: Node, ctx: Context): ChildNode | null | void => { console.log('walk', node); // ... } 复制代码
排除换行符"\n "
对应的文本节点,打印顺序以下:
walk div walk <button>add 1</button> walk "add 1" walk <p>0</p> walk "0" 复制代码
从打印结果看,这是个深度优先遍历(若是有子节点就遍历子节点,没有子节点就遍历兄弟节点)
显然,petite-vue
mount
时采用深度优先遍历,并对遍历到的每一个与上下文状态相关的DOM
节点进行处理。
在Demo
中,上下文包含状态{count: 0}
:
createApp({count: 0}).mount() 复制代码
在遍历后<p>{{count}}</p>
变为<p>0</p>
。
肯定双向绑定的粒度
接下来咱们须要确认双向绑定的做用范围,即:
触发更新后,多大范围的
DOM
会被从新遍历并执行相应DOM
操做?
打开Performance
后,点击<button>add 1</button>
触发更新:
能够看到,没有任何walk
、walkChildren
(或相似遍历过程),只调用了reactiveEffect
一个方法就更新了DOM
。
这意味着mount
时的深度优先遍历创建了状态
与更新DOM的方法
之间一一对应的关系。
由于对应关系肯定了,就再也不须要额外的遍历过程肯定须要变化的DOM
。
当更新状态
后,只须要找到与他有关系的更新DOM的方法
执行就行。
好比:将count
状态与以下函数创建联系:
function setCount(value) { p.textContent = value; } 复制代码
每当count
变化后调用setCount(count)
就能更新p
对应DOM
。
因此,petite-vue
的工做原理,主要包括两点:
-
mount
时深度优先遍历DOM
,对有状态的DOM
(好比<p>{{count}}</p>
)创建状态
与更新DOM的方法
之间一一对应的关系 -
update
时找到该状态
对应的更新DOM的方法
并执行
能够看到,即便不深刻源码,也能大致了解工做流程。
若是你想更进一步,好比了解关系是如何创建的(涉及到响应式更新),那么就须要深刻源码了。
这里推荐Vue Mastery
的Vue 3 Reactivity
课程,能够补齐响应式更新这块知识。
总结
本文介绍了复杂框架源码的阅读办法 —— 即从抽象到具体。
-
从
mount
时与update
时的调用栈推导出总体工做流程
-
从
总体工做流程
中发现核心知识 —— 响应式更新
当掌握总体工做流程
与响应式更新
后,再阅读本身感兴趣的部分才不至于陷入庞大的代码量中。
你,学废了么?
最后,创做不易,若是对你们有所帮助,但愿你们点赞支持,有什么问题也能够在评论区里讨论😄~