总述:架构革命性升级
Vue3 是对 Vue2 的全面重构而非简单更新,核心变化可概括为:
- 响应式系统:
Object.defineProperty
→Proxy
重构 - 虚拟DOM:静态标记 + PatchFlag 优化
- 代码组织:Options API → Composition API
- 打包机制:支持 Tree-shaking 的模块化架构
- 类型系统:全面拥抱 TypeScript
以下通过源码对比详细解析核心差异:
一、响应式系统重构(核心变化)
1.1 Vue2 响应式实现
源码位置:src/core/observer/index.js
// 简化版实现
export function defineReactive(obj, key) {
const dep = new Dep()
let val = obj[key]
Object.defineProperty(obj, key, {
get() {
dep.depend() // 收集依赖
return val
},
set(newVal) {
val = newVal
dep.notify() // 触发更新
}
})
}
缺陷分析:
- 递归遍历所有属性(性能差)
- 无法检测新增/删除属性(需
Vue.set
) - 数组需要特殊处理(重写7个方法)
1.2 Vue3 响应式实现
源码位置:packages/reactivity/src/reactive.ts
// 基于Proxy的实现
function createReactiveObject(target) {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key) // 追踪依赖
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver)
trigger(target, key) // 触发更新
return result
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
trigger(target, key) // 删除也能触发更新
return result
}
})
}
优势对比:
特性 | Vue2 | Vue3 | 提升效果 |
---|---|---|---|
检测能力 | 仅限已有属性 | 全属性 | 无需Vue.set |
数组支持 | 需重写方法 | 原生支持 | 直接索引赋值 |
集合类型 | 不支持Map/Set | 原生支持 | 扩展数据结构支持 |
初始化性能 | O(n)递归遍历 | O(1)代理 | 大型对象快40% |
二、虚拟DOM优化(性能飞跃)
2.1 Vue2 Diff算法
源码位置:src/core/vdom/patch.js
// 全量比较策略
function patchVnode(oldVnode, vnode) {
// 1. 比较标签类型
if (oldVnode.tag !== vnode.tag) {
replaceVnode(oldVnode, vnode)
return
}
// 2. 比较属性
const oldProps = oldVnode.data.attrs || {}
const newProps = vnode.data.attrs || {}
updateAttrs(oldVnode.elm, oldProps, newProps)
// 3. 比较子节点(递归)
updateChildren(oldVnode.elm, oldVnode.children, vnode.children)
}
问题:即使静态内容也要遍历比较
2.2 Vue3 PatchFlag 优化
源码位置:packages/runtime-core/src/vnode.ts
// PatchFlag 标记(二进制位)
export const enum PatchFlags {
TEXT = 1, // 动态文本
CLASS = 1 << 1, // 动态class
STYLE = 1 << 2, // 动态style
PROPS = 1 << 3, // 动态属性(非class/style)
FULL_PROPS = 1 << 4, // 动态key需全量比较
HYDRATE_EVENTS = 1 << 5,
STABLE_FRAGMENT = 1 << 6,
KEYED_FRAGMENT = 1 << 7,
UNKEYED_FRAGMENT = 1 << 8,
NEED_PATCH = 1 << 9,
DYNAMIC_SLOTS = 1 << 10,
HOISTED = -1, // 静态节点
BAIL = -2 // 差异太大需全量比较
}
// 编译后生成的代码
const _hoisted_1 = /*#__PURE__*/_createVNode("h1", null, "静态标题", -1 /* HOISTED */)
function render(_ctx) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1,
_createVNode("p", null, _toDisplayString(_ctx.dynamicText), 1 /* TEXT */)
]))
}
优化效果:
- 静态节点提升(HOISTED):跳过比较
- 动态标记(TEXT/PROPS):只比动态部分
- 更新性能提升:最高200%(官方Benchmark)
三、Composition API(开发范式革命)
3.1 Options API vs Composition API
Vue2 实现计数器:
// src/components/Counter.vue
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
},
computed: {
double() {
return this.count * 2
}
}
}
Vue3 Composition API实现:
// src/components/Counter.vue
import { ref, computed } from 'vue'
export default {
setup() {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, double, increment }
}
}
3.2 源码实现解析
核心源码:packages/runtime-core/src/component.ts
// 组件实例创建流程
function setupComponent(instance) {
// 解析Options API
const { setup } = instance.type
if (setup) {
// 创建setup上下文
const setupContext = createSetupContext(instance)
// 执行setup函数
const setupResult = callWithErrorHandling(
setup, instance, [instance.props, setupContext]
)
// 处理返回结果
if (isFunction(setupResult)) {
// 返回渲染函数
instance.render = setupResult
} else if (isObject(setupResult)) {
// 绑定到实例上下文
instance.setupState = proxyRefs(setupResult)
}
}
// 兼容Options API
if (!instance.render) {
instance.render = instance.type.render || NOOP
}
}
设计优势:
-
逻辑复用:自定义Hook代替Mixins
// useCounter.js import { ref, computed } from 'vue' export function useCounter(initial = 0) { const count = ref(initial) const double = computed(() => count.value * 2) const increment = () => count.value++ return { count, double, increment } }
-
更好的TS支持:完整类型推导
-
代码组织:相关逻辑集中管理
四、生命周期与API变化
4.1 生命周期映射
Vue2 | Vue3 Composition | 源码位置(Vue3) |
---|---|---|
beforeCreate | 使用setup()替代 | 在createComponentInstance之前 |
created | 使用setup()替代 | 在setupComponent之后 |
beforeMount | onBeforeMount | packages/runtime-core/src/apiLifecycle.ts |
mounted | onMounted | 同上 |
beforeUpdate | onBeforeUpdate | 同上 |
updated | onUpdated | 同上 |
beforeDestroy | onBeforeUnmount | 同上 |
destroyed | onUnmounted | 同上 |
4.2 全局API变化
Vue2 全局API:
// src/core/global-api/index.js
export function initGlobalAPI(Vue) {
Vue.config = {...}
Vue.util = {...}
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
Vue.observable = observable
Vue.options = {}
// 注册内置组件
initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)
}
Vue3 模块化API:
// packages/runtime-core/src/apiCreateApp.ts
export function createAppAPI(render) {
return function createApp(rootComponent, rootProps = null) {
const context = createAppContext()
const app: App = {
_component: rootComponent,
_props: rootProps,
_container: null,
component(name, component) {
context.components[name] = component
return app
},
directive(name, directive) {
context.directives[name] = directive
return app
},
mount(rootContainer) {
// 挂载逻辑
}
}
return app
}
}
变化核心:
- 全局API改为实例方法(避免污染)
- 支持多应用实例(
createApp()
) - Tree-shaking:未使用API不打包
五、模板编译优化(编译器升级)
5.1 Vue2 模板编译
编译产物:
function render() {
with(this) {
return _c('div', [
_c('h1', [_v("静态标题")]),
_c('p', [_v(_s(dynamicText))])
])
}
}
问题:无静态动态区分,全量Diff
5.2 Vue3 编译优化
源码位置:packages/compiler-core/src/transform.ts
// PatchFlag 生成逻辑
export const transformElement = (node, context) => {
// 标记动态属性
const patchFlag = getPatchFlag(node)
return () => {
if (patchFlag !== PatchFlags.HOISTED) {
node.codegenNode = createVNodeCall(
context,
node.tag,
node.props,
node.children,
patchFlag
)
}
}
}
// 编译产物(带PatchFlag)
import { createVNode as _createVNode, openBlock as _openBlock } from "vue"
export function render(_ctx) {
return (_openBlock(),
_createVNode("div", null, [
_createVNode("h1", null, "静态标题"),
_createVNode("p", null, _ctx.dynamicText, 1 /* TEXT */)
]))
}
核心优化点:
- 静态节点提升(HOISTED):渲染函数外创建
- 静态属性提升:跳过属性比较
- PatchFlag标记:指导运行时Diff
- 事件缓存:避免重复创建
六、TypeScript支持(工程化升级)
6.1 Vue2 的TS困境
问题表现:
import Vue from 'vue'
const Component = Vue.extend({
props: {
message: String // 类型声明有限
},
methods: {
handleClick() {
this.$emit('custom') // 无法推断事件类型
}
}
})
6.2 Vue3 全面TS重构
源码结构:
packages/
compiler-core/ # TS实现
runtime-core/ # TS实现
reactivity/ # TS实现
...
组件类型声明:
// packages/runtime-core/src/apiDefineComponent.ts
export function defineComponent(options) {
return isFunction(options)
? { setup: options }
: options
}
// 使用示例
import { defineComponent } from 'vue'
export default defineComponent({
props: {
message: {
type: String,
required: true
}
},
emits: ['change'], // 声明事件
setup(props, { emit }) {
props.message // 自动推断为string
function handleChange() {
emit('change') // 类型安全
}
}
})
优势:
- 源码使用TS重写(覆盖率100%)
- 完善的类型定义(组件/API/插件)
- 模板类型检查(Volar插件支持)
总结:Vue3的全面进化
三大核心突破
- 性能飞跃:
- 响应式:Proxy替代defineProperty
- 虚拟DOM:PatchFlag静态标记
- 包体积:Tree-shaking减少41%体积
- 开发体验:
- Composition API逻辑复用
- 更好的TypeScript支持
- Fragment/Teleport等新特性
- 工程化:
- 模块化架构(@vue/runtime-core等)
- 自定义渲染器(Canvas/Native支持)
- 编译时优化(预编译静态节点)
Vue3 不是简单的版本迭代,而是前端框架设计的范式转变。其架构思想已影响 React 18、Svelte 等框架设计,代表了现代前端框架的发展方向。掌握 Vue3 不仅是为了使用新特性,更是理解前端框架设计思想的必修课。