Vue 3 代表了 Vue 框架的一次重大飞跃。它在性能、开发体验(特别是 Composition API 和 TS)、灵活性和功能上都带来了显著的提升。虽然 Composition API 需要一些时间适应,但其带来的逻辑组织、复用和维护性的优势对于构建现代、复杂的前端应用是至关重要的。对于新项目,Vue 3 是毋庸置疑的选择;对于老项目,应积极评估并规划向 Vue 3 的迁移,Vue2在2023年底已经停止维护。
一. Vue2和Vue3区别概览
特性 | Vue2 | Vue3 |
架构&响应式 |
Options API(选项式API主导) |
Composition API(组合式API主导)+ Options API |
响应式原理 |
Object.defineProprety数据劫持 |
Proxy数据代理 |
性能 |
良好 |
显著提升 |
构建工具 |
Vue CLI(基于 Webpack) |
Vite |
状态管理 |
VueX |
Pinia |
TypeScript |
弱支持,需额外配置 |
原生支持 |
Fragment |
单根节点限制 |
支持多根节点 |
Tree-Shaking |
有限支持 |
原生支持 |
Teleport |
无 |
内置 (<Teleport>) |
Suspense |
无 |
内置 |
全局 API |
Vue 构造函数挂载,全局配置 |
创建应用实例(createApp),避免全局污染 |
事件 API |
$on, $off, $once |
删除 |
v-model |
1个组件仅1个 v-model |
支持多个 v-model (带参数),组件双向绑定更灵活 |
指令钩子 |
bind, inserted 等 |
与组件生命周期对齐,命名和语义更一致 |
二. 区别详解
1. 响应式原理
Vue2 (Object.defineProperty)
-
原理
通过递归遍历对象属性,用 Object.defineProperty
的 getter/setter
拦截属性访问和修改。
-
局限性
- 无法检测属性的添加或者删除:需要使用Vue.set/Vue.delete或this.$set/this.$delete。
- 数组的响应式需要特殊处理:通过重写数据的变异方法(如:push,pop,shift,unshiftsplice,sort,reverse)实现。直接通过索引修改元素(arr[index] = newValue)或修改数组长度(arr.length = newLength)不是响应式的,也需要用Vue.set或者变异方法。
- 性能开销:初始化时需要递归遍历整个数组,对于大型对象或嵌套结构开销较大。
Vue3(ES6 Proxy)
-
原理
使用 ES6 的 Proxy
对象包裹目标对象。Proxy
可以拦截对象上几乎所有的操作(包括属性读取、设置、添加、删除、in
操作符、Object.keys
等)。
-
优势
-
全面拦截:原生支持检测属性的添加和删除。
-
原生数组响应式:直接通过索引修改元素或修改
length
属性也能触发更新(因为Proxy
能拦截set
和deleteProperty
操作符,即使作用于数组索引)。 -
支持 Map, Set, WeakMap, WeakSet:这些集合类型也能被直接代理为响应式对象。
-
更好的性能:惰性代理(按需触发代理),避免了初始化时的全量递归遍历(对于嵌套对象,Vue 3 也是在访问时才递归代理下一层)。
-
更小的内存占用:
Proxy
对象本身比defineProperty
定义的多个getter/setter
更轻量。
案例分析
Vue2
export default {
data() {
return {
formFields: [
{ id: 1, value: '' }
]
};
},
methods: {
addField() {
// 必须使用 $set 或 push 来确保新字段是响应式的
this.formFields.push({ id: Date.now(), value: '' });
// 错误做法:this.formFields[this.formFields.length] = { id: Date.now(), value: '' };
// 不会触发更新
},
removeField(index) {
// 必须使用 $delete 或 splice 来确保删除是响应式的
this.formFields.splice(index, 1);
// 错误做法:delete this.formFields[index]; // 不会触发更新,且数组长度不变
},
updateField(index, newValue) {
// 直接修改数组元素的属性是响应式的,因为对象本身已被 defineProperty 处理
this.formFields[index].value = newValue;
}
}
};
Vue3
<script setup>
import { reactive } from 'vue';
const formFields = reactive([
{ id: 1, value: '' }
]);
const addField = () => {
// 直接 push 或通过索引赋值新元素都行!
formFields.push({ id: Date.now(), value: '' });
// 或者:formFields[formFields.length] = { id: Date.now(), value: '' }; // 同样响应式!
};
const removeField = (index) => {
// 直接 delete 索引或 splice 都行!
delete formFields[index]; // 会触发更新,数组长度会变短!
// 或者:formFields.splice(index, 1);
};
const updateField = (index, newValue) => {
formFields[index].value = newValue; // 和 Vue 2 一样正常
};
</script>
结论
Vue 3 的响应式系统让处理动态数据结构(尤其是数组操作)变得直观且不易出错,无需记忆特殊的 API ($set
, $delete
)。开发者心智负担更小,代码更简洁。
2. Options API 和Composition API
Vue 2 (Options API)
通过定义不同的选项对象来组织代码:data
, methods
, computed
, watch
, props
, hooks
等。
-
优点: 结构清晰,对于简单组件非常直观,学习曲线相对平缓。
-
缺点:
-
逻辑关注点分离: 一个功能的逻辑(数据、计算属性、方法、生命周期钩子)可能分散在不同的选项中。当组件变得复杂时,理解和维护代码变得困难,需要上下滚动查找相关代码。
-
类型推断支持弱: 与 TypeScript 集成相对笨拙。
Vue 3 (Composition API)
引入setup()函数作为组建的入口点,它接收props和context,在beforeCreate和created之间执行。在setup()内部,你可以使用一系列响应式API(ref、reactive、computed、watch、watchEffect)和生命周期钩子函数(onMounted、onUpdated、onUnmounted等)来声明响应式状态、计算属性侦听器以及执行副作用。
-
优点:
- 更好的逻辑组织与复用: 可以将与同一功能相关的所有代码(状态、计算、方法、副作用)紧密地组织在一起。通过 Composables 实现干净、灵活、无副作用的逻辑复用。
- 更灵活的代码组织: 不受选项位置限制,可以按逻辑而非选项类型组织代码。
- 更强的 TypeScript 支持: 函数式 API 天生对类型推断更友好。
- 更小的生产包: 由于更好的 Tree-Shaking,使用 Composition API 编写的代码通常能生成更小的包。
-
结论: Composition API 将紧密相关的逻辑(状态、计算、侦听、副作用)组织在一起,显著提高了复杂组件的可读性和可维护性。通过 Composables,逻辑复用变得极其简单、清晰且无副作用,避免了 mixin 的缺点。代码组织更加自由灵活。
3. 构建工具
Vue2(Vue CLI)
Vue CLI(Command Line Interface)是Vue官方提供的标准构建工具,它基于Webpack。它为开发人员提供了一套完整的项目脚手架和开发环境。
-
特点
- 基于Webpack,拥有强大的插件系统;
- 提供了`vue create`命令快速创建项目;
- 有图形化界面(通过`vue ui`命令);
- 支持热重载(Hot Module Replacement, HMR);
- 集成了Babel、ESLint、TypeScript等工具。
-
缺点
随着项目增大,Webpack的启动时间和热更新速度会变慢。
Vue3(Vite)
浏览器原生ES,在开发环境下无需打包,启动速度极快。
-
特点
- 极速的服务启动:利用ESM,不需要打包,按需编译;
- 快速的热更新:只更新修改的模块,不会重新打包整个项目;
- 开箱即用:支持TypeScript、JSX、CSS预处理器等;
- 支持Vue 2和Vue 3(通过插件);
- 配置文件为`vite.config.js`,语法简单。
总结
特性 | Vue CLI(Webpack) | Vite |
冷启动时间 | 随项目增大线程增大,较慢 | 毫秒级启动(利用浏览器原生ESM) |
热更新(HMR) | 增量重建,中等速度 | 按需编译,极快(<100ms) |
构建核心 | Webpack |
开发环境:ESM; 生产环境:Rollup |
TypeScript | 需要额外的loader和配置 | 原生支持 |
CSS | 通过css-loader等处理 | 内置PostCSS、Sass、Less支持 |
未来趋势 | 维护阶段 | 官方主推 |
4. 状态管理
Vue2(Vuex)
-
核心概念
- State:集中存储全局状态(响应式)数据。
- Mutations:唯一同步修改状态的方式,通过commit触发。
- Actions:处理异步操作,通过dispatch触发并提交Mutation。
- Getters:派生计算属性(类似computed)。
- Modules:分割复杂状态树,支持嵌套和命名空间。
-
缺点
- 强制区分同步(Mutations)和异步(Actions),代码冗余。
- TypeScript 支持弱,需手动声明类型。
Vue3(pinia)
-
核心概念
- 简化结构:移除 Mutations,允许在
actions
中直接同步/异步修改状态; - 更轻量:体积约 1KB,基于 Vue 3 的
reactive
和ref
实现响应式; - 类型友好:内置 TypeScript 支持,自动推导类型。
-
优势
- 减少样板代码,逻辑更直观;
- 模块化更自然:每个 Store 独立文件,无需嵌套命名空间。
总结
特性 | Vuex(Vue2) | Pinia(Vue3) |
状态修改 | 必须通过commit(Mutation)或dispatch(Action) | 可直接修改 |
TypeScript | 需手动声明类型,配置复杂 | 开箱即用,自动类型推断 |
模块化 | 需配置namespaced: true,结构臃肿 | 文件即模块,天然隔离 |
热重载 | 不支持 | 开发模式下支持Store热更新 |
插件生态 | 成熟 | 轻量插件 |
5. 生命周期
Vue2和Vue3生命周期钩子函数整体上变化不大,只是大部分名称上加了“on”
,功能类似。但是Vue3 使用生命周期钩子函数时需要先引入
,而 Vue2 可以直接调用。
Vue 2 钩子函数 | Vue 3 钩子函数 | 说明 |
beforeCreate | setup() | 组件初始化前,Vue 3 中不需要,由 setup() 取代 |
created | setup() | 组件创建完成,Vue 3 中不需要,由 setup() 取代 |
beforeMount | onBeforeMount | 挂载到 DOM 前 |
mounted | onMounted | 挂载到 DOM 后 |
beforeUpdate | onBeforeUpdate | 数据变化导致 DOM 更新前 |
updated | onUpdated | 数据变化导致 DOM 更新后 |
beforeDestroy | onBeforeUnmount | 组件卸载前,Vue3重命名 |
destroyed | onUnmounted | 组件卸载后,Vue3重命名 |
activated | onActivated | <keep-alive> 缓存组件激活时 |
deactivated | onDeactivated | <keep-alive> 缓存组件停用时 |
6. 性能优化
特性 | Vue2 | Vue3 | 说明 |
Fragment | 单根节点限制 | 支持多根节点 | 减少无用div嵌套 |
Tree-shaking | 不支持 | 按需打包,未使用模块不引入 | 打包体积降低40%以上,显著提升用户体验 |
Teleport | 不支持 | <Teleport to="body">内置支持 | 解决模态框层级问题 |
Suspense | 不支持 | 异步组件加载状态管理 | 优化用户体验 |
v-model | 单组件仅支持一个 | 支持多个 | 表单组件开发更灵活 |
全局API | Vue构造函数 | createApp()隔离实例 | 避免全局污染 |
虚拟DOM | 全量对比所有节点 | Patch Flag标记动态节点,虚拟DOM Diff时仅对比带标记的节点,跳过静态内容 | Diff速度提升50%以上 |
静态内容处理 | 每次重新渲染 | 静态节点提升(Hoist Static),复用常量 | 将静态节点(如<div>Hello</div>)提取为常量,避免重复创建,直接复用 |
事件处理 | 每次渲染新建函数 | 缓存函数实例 |
GC压力降低,高频交互流畅提升 |
7. 总结
- Vue2使用Object.defineProperty劫持数据,Vue3使用Proxy代理数据,简化了响应式(属性增删、数组索引修改)操作,提升了性能;
- Vue2使用Options API(选项式API),Vue3使用Composition API(组合式API),逻辑复用更灵活,避免 Mixins 问题,更好的 支持TypeScript ,适合大型项目;
- Vue2使用Vue2+Vue CLI+Vuex,Vue3使用Vue3+Vite+Pinia,Vue3API设计简洁,打包体积小,渲染速度快,更新渲染快,占用内存少
- Vue3的一些新特性,如Tree-shaking、Teleport、Suspense以及虚拟DOM等,优化性能,提升用户体验和开发效率;
- 官方已经停止维护Vue2(2023年12月31日停止)。