Vue | 2020-12-27 12:23:55 1128次 2次
开篇之前先看下 mvvm 实现
代码结构
compiler-core: 平台无关的编译
compiler-dom: 浏览器的编译
compiler-sfc: 单文件编译部分
compiler-ssr: 服务端渲染编译相关
reactivity: 响应系统
runtime-core: 运行时与创建实例相关代码
runtime-dom: 针对浏览器的运行时。包括DOM API,属性,事件处理等
runtime-test: 测试代码
server-renderer: 服务端渲染
shared: 工具库
size-check: 测试代码体积
template-explorer: 内部使用的编译文件浏览工具
vue: 主入口文件
通过文件结构的划分,可以看出 vue 包含三大模块:响应式系统、编译模块、运行时(调度、diff 等)
源码调试
通过 yarn build -s 打包 vue3 (生成 source map),代码中通过 umd 方式引入调试。
其次是通过【单元测试】中的测试用例来辅助理解。
Reactive
Vue2 通过 observer 进行数据的变化监听,watcher 通过 dep 收集自身,保存界面渲染回调,当有数据变化时,会触发 dep 中任务列表,从而更新页面。watcher 和 compiler 绑定,watcher 绑定到 dep 静态属性上之后,触发一次数据获取,在 observer 进行了 watch 依赖收集,从而可以监听数据变化触发这些依赖。
Vue3 核心是通过 Proxy 进行数据的劫持,取值 track,赋值 trigger。当在 effect 中取值时,存储的是用户创建的各个对象
targetMap(weakMap)【多次的reciver】 --> depsMap(Map)【reciver数据中不同的键】 --> dep(Set)[用来发布订阅的执行 effect]
赋值时候,通过如上的数据结构,找到修改key,来执行所有的effect回调即可,整体设计结构如下图:
避免多个 effect 中再次设置被监听的值赋值操作导致的重复渲染问题,可以通过一个栈记录所有的信息,避免重复添加,再通过 activeEffect 判断避免重复执行。
Ref
function ref(raw){ const r = { get value(){ track(r, 'value'); return raw; }, set value(newValue){ raw = newValue; trigger(r, 'value'); } } return r; }
Computed
function computed(getter){ const res = ref(); watchEffect(() => { res.value = getter(); }) return res; }
响应式的部分内容比较清晰简单,就是负责数据的响应监听,具体代码请参考 svu 的简易实现。
2人赞