一句话总结
Vue3 的升级是四个方向:响应式(defineProperty → Proxy,彻底解决增删监听)、代码组织(Options API → Composition API,逻辑按功能聚合、可抽 composable 复用)、性能(静态提升、PatchFlags、Block Tree、事件缓存,虚拟 DOM 只 diff 动态内容)、生态(Fragment/Teleport/Suspense、完整 TS 支持、Tree-shaking 减体积)。
初级理解
Composition API 的核心动机:Options API 把一个功能拆散在 data/methods/computed/watch 各处("跳来跳去写代码"),逻辑复用靠 mixin(来源不明、命名冲突)。Composition API 让同一个功能写在一起,复用就是一个普通函数。
三大新组件:
- Fragment:模板支持多根节点(Vue2 必须单根)
- Teleport:把子树渲染到 DOM 任意位置——弹窗/抽屉传到 body 下,彻底解决父级 overflow/z-index 裁剪问题
- Suspense:等待异步组件(含 setup async)时渲染 fallback 加载态
中级深入
<script setup> 语法糖(面试必问):顶层声明的变量/函数/导入自动暴露给模板,组件导入即注册(无需 components 选项),编译产物更少、运行更快;内置宏 defineProps/defineEmits/defineExpose/defineModel/defineOptions 无需导入、编译期处理。
生命周期映射:setup 替代 beforeCreate/created;onMounted/onUpdated/onUnmounted/onBeforeUnmount 等一一对应;新增 onErrorCaptured 的组合式写法;keep-alive 组件的 onActivated/onDeactivated。
性能提升点(中级要能说全):① Proxy 懒代理,初始化不再递归全量劫持;② 静态提升:静态 vnode 只创建一次;③ PatchFlags + Block Tree:diff 只遍历动态节点、只比动态属性;④ 事件缓存:inline handler 不再每次渲染重建;⑤ Tree-shaking:没用的内置组件/指令(Transition、v-model 修饰符等)打包时被裁剪,体积更小。
v-model 变化:Vue2 默认 value/input 且一个组件只能一个;Vue3 改为 modelValue / update:modelValue,支持 v-model:title 多个双向绑定。
高级拓展
编译优化细节(拉开差距的部分):PatchFlag 是位标记,如 1 /* TEXT */、2 /* CLASS */、8 /* PROPS */——diff 时判断 flag:只有 TEXT 就只比 children 文本;PROPS 则附带动态属性名数组,精确到字段。Block 收集动态后代节点时"拍平"了层级,无论嵌套多深,更新都只走一条扁平列表。
主要破坏性变更(迁移必查清单):
- 响应式系统换 Proxy → 移除 $set/$delete/Vue.set、Vue.observable(换 reactive)
- 移除 $on/$off/$once(事件总线)、filters(用计算属性/方法)、函数式组件语法、$children
- 异步组件改 defineAsyncComponent;v-if/v-for 优先级反转;scoped 样式深度选择器 ::v-deep → :deep()
- 全局 API 改实例化:Vue.use/global properties → app.use/app.config.globalProperties
TS 支持:源码用 TS 重写只是基础,关键是 defineProps<{ id: number }>() 类型即校验、ref/computed 全链路类型推导、模板表达式在 IDE 里有完整类型提示(Volar)。
实战场景
场景一:mixin 迁移为 composable
场景二:弹窗被父级 overflow 裁剪
场景三:Vue2 项目平滑升级
面试模拟
Q:Composition API 和 Options API 的本质区别?
A:组织维度不同——Options 按选项类型切割代码(一个功能分散四处),Composition 按逻辑功能聚合(一个功能收拢在一个作用域内),且复用单元从"隐式混入"变成"显式函数"。运行时性能没有本质差异,核心收益在可维护性和逻辑复用;大型组件还能避免 this 指向的心智负担(setup 里没有 this)。
Q:Vue3 快在哪里?请从编译和运行时两个角度说。
A:编译时——静态提升、PatchFlags、Block Tree、事件缓存,把"哪些是动态的"提前算好;运行时——Proxy 懒代理让初始化开销从 O(属性总数) 变为 O(访问到的属性),diff 只处理动态节点集合。加上 Tree-shaking 减小包体积、更快解析(与 Proxy 无关但编译器输出精简),官方数据渲染更新性能有 1.3~2 倍提升、内存占用显著降低。
Q:defineExpose 是干什么的?为什么需要它?
A:script setup 的组件默认是"封闭"的——外部通过模板 ref 拿到实例也访问不到内部绑定(Vue3 显式关闭了隐式暴露,避免脆弱耦合)。defineExpose({ reset, focus }) 白名单式声明哪些方法/状态可被父组件调用,这是把"默认全开"改为"默认关闭 + 显式声明"的 API 设计。