《Vue.js设计与实现》笔记 第3章:Vue.js 3 的设计思路
Vue.js设计与实现 第三章:Vue.js 3 的设计思路
本章导读
Vue3 的核心可以拆分为三大模块:
Vue3
├── 响应式系统(Reactivity)
├── 渲染器(Renderer)
└── 编译器(Compiler)
其中:
- 响应式系统负责数据变化检测
- 渲染器负责更新视图
- 编译器负责优化模板
本章主要介绍:
- Vue3整体工作流程
- 响应式系统原理
- 渲染器工作原理
- 编译器优化思想
一、声明式描述UI
Vue属于声明式框架。
开发者只需要描述:
<div>Hello Vue</div>
或者:
<div>{{ msg }}</div>
而不需要:
document.createElement()
appendChild()
setAttribute()
声明式的优势
例如:
命令式:
const div = document.createElement('div')
div.innerText = 'Hello Vue'
document.body.appendChild(div)
声明式:
<div>Hello Vue</div>
对比:
| 命令式 | 声明式 |
|---|---|
| 关注过程 | 关注结果 |
| 代码量大 | 代码量少 |
| 灵活性高 | 可维护性高 |
| 开发效率低 | 开发效率高 |
二、渲染器(Renderer)
什么是渲染器
渲染器的职责:
将虚拟DOM转换为真实渲染目标
例如:
VNode
↓
Renderer
↓
DOM
渲染器并不一定渲染DOM
Vue3设计目标:
跨平台
因此:
VNode
↓
Renderer
├── 浏览器DOM
├── SSR字符串
├── 小程序
└── Native
自定义渲染器
Vue提供:
createRenderer()
允许开发者实现:
- Canvas渲染器
- WebGL渲染器
- 小程序渲染器
渲染器核心能力
挂载(Mount)
初次创建DOM
更新(Patch)
比较新旧VNode
更新变化部分
卸载(Unmount)
移除DOM
渲染流程
VNode
↓
Mount
↓
DOM
数据变化
VNode
↓
Patch
↓
更新DOM
三、虚拟DOM
什么是VNode
VNode:
Virtual Node
虚拟节点
本质:
const vnode = {
type: 'div',
props: {
id: 'app'
},
children: 'Hello Vue'
}
为什么需要VNode
目的:
统一描述UI
这样:
组件
HTML
SVG
Fragment
都能用统一结构表示。
VNode优势
跨平台
同一个VNode
可以渲染到不同平台
更新优化
通过Diff算法:
比较VNode
更新真实DOM
四、响应式系统
什么是响应式
核心思想:
数据变化
自动更新视图
例如:
state.count++
界面自动刷新。
响应式示例
普通对象:
const obj = {
text: 'hello'
}
修改:
obj.text = 'world'
页面不会更新。
Vue响应式:
const obj = reactive({
text: 'hello'
})
修改:
obj.text = 'world'
页面自动更新。
五、副作用函数(Effect)
什么是副作用
副作用:
函数执行会产生额外影响
例如:
document.title = 'Vue'
修改页面标题。
Effect概念
例如:
effect(() => {
document.body.innerText = obj.text
})
作用:
依赖数据变化
自动重新执行
工作流程
effect执行
↓
读取响应式数据
↓
收集依赖
数据变化
↓
触发effect
↓
重新执行
六、依赖收集
为什么需要依赖收集
例如:
effect(() => {
console.log(obj.text)
})
Vue需要知道:
哪个effect依赖了obj.text
否则无法触发更新。
收集过程
读取属性
↓
track()
↓
建立依赖关系
例如:
obj.text
↓
effect
建立映射。
七、触发更新
数据修改
例如:
obj.text = 'Vue3'
执行:
trigger()
更新流程
set操作
↓
trigger()
↓
找到依赖
↓
执行effect
整体流程
读取数据
↓
track()
修改数据
↓
trigger()
重新执行effect
八、Vue3为何使用Proxy
Vue2的问题
Vue2使用:
Object.defineProperty()
存在限制:
无法监听新增属性
obj.newProp = 123
无法监听。
无法监听删除属性
delete obj.foo
无法监听。
无法监听数组长度变化
arr.length = 0
存在问题。
Vue3解决方案
使用:
Proxy
例如:
const obj = new Proxy(data,{
get(){},
set(){}
})
Proxy优势
监听新增属性
obj.foo = 1
可以监听。
监听删除属性
delete obj.foo
可以监听。
监听数组变化
arr.push()
可以监听。
监听Map和Set
map.set()
set.add()
都能监听。
九、编译器(Compiler)
什么是编译器
作用:
Template
↓
Render Function
示例
模板:
<div>{{ msg }}</div>
编译后:
render() {
return h('div', msg)
}
编译器作用
提升开发体验
开发者写:
Template
即可。
提升运行性能
编译阶段提前分析。
十、编译优化
Patch Flag
标记动态内容:
PatchFlags.TEXT
表示:
只有文本会变化
Static Hoist
静态提升:
<span>静态节点</span>
只创建一次。
Block Tree
收集动态节点:
更新时
直接访问动态节点
减少Diff范围。
十一、Vue3整体工作流程
首次渲染
Template
↓
Compiler
↓
Render Function
↓
VNode
↓
Renderer
↓
DOM
数据更新
修改数据
↓
Proxy拦截
↓
trigger()
↓
effect重新执行
↓
生成新VNode
↓
Patch
↓
更新DOM
Vue3核心架构图
Template
│
▼
Compiler
│
▼
Render Function
│
▼
VNode
│
▼
Renderer
│
▼
DOM
Reactive Data
│
▼
Proxy
│
▼
track / trigger
│
▼
effect
│
▼
重新执行Render
│
▼
更新DOM
高频面试题
Vue3由哪些核心模块组成?
Reactivity
Renderer
Compiler
Renderer作用是什么?
负责:
VNode → 渲染目标
包括:
- Mount
- Patch
- Unmount
什么是VNode?
使用JavaScript对象描述UI结构。
什么是响应式?
数据变化自动触发更新。
effect的作用是什么?
注册副作用函数。
数据变化时自动重新执行。
track和trigger分别做什么?
track
收集依赖
trigger
触发依赖
Vue3为什么使用Proxy?
解决Vue2:
新增属性监听
删除属性监听
数组监听
Map监听
等问题。
编译器的作用是什么?
Template
↓
Render Function
同时完成编译优化。
第三章核心知识图谱
Vue3架构
├── Reactivity
│ ├── Proxy
│ ├── effect
│ ├── track
│ └── trigger
│
├── Renderer
│ ├── Mount
│ ├── Patch
│ └── Unmount
│
├── VNode
│
├── Compiler
│ ├── Template
│ ├── Render Function
│ ├── Patch Flag
│ ├── Static Hoist
│ └── Block Tree
│
└── 数据驱动视图
本章总结
Vue3整体由三大核心模块组成:
Compiler
Renderer
Reactivity
工作流程:
Template
↓
Compiler
↓
Render Function
↓
VNode
↓
Renderer
↓
DOM
响应式更新流程:
Proxy
↓
track
↓
trigger
↓
effect
↓
重新渲染
Vue3通过:
- Proxy
- VNode
- Renderer
- Compiler
构建出完整的:
数据驱动视图系统
第三章实际上是后续源码章节的总纲。
后面第4~6章会正式开始实现:
- 响应式系统(effect、track、trigger)
- Proxy代理对象
- 调度执行机制
这些内容是整本书最重要的部分,也是 Vue 面试和源码学习的核心。

浙公网安备 33010602011771号