vue2和vue3的对比
核心总结(一句话概括)
- Vue 2:基于
Options API
的成熟稳定的框架,通过一系列选项(data
,methods
,computed
等)来组织代码,简单易上手,但大型项目代码组织性会变差。 - Vue 3:基于
Composition API
的现代化框架,允许通过逻辑功能(而非选项类型)来组织代码,提供了更好的逻辑复用、TypeScript 支持和更强的性能。
1. 架构与响应式原理的重构(最根本的区别)
这是 Vue 3 最核心、最重要的升级,带来了巨大的性能提升和功能突破。
特性 | Vue 2 | Vue 3 |
---|---|---|
响应式系统 | Object.defineProperty | Proxy |
工作机制 | 递归遍历 data 中的所有属性,使用 getter/setter 进行劫持。无法检测属性的添加或删除,需要使用 Vue.set /Vue.delete 。对数组的方法需要重写(如 push , pop )。 | 直接代理整个对象,拦截对象的所有操作(包括增、删、改、查)。天生支持动态添加和删除属性。对数组和Map、Set等集合类型支持完美。 |
性能影响 | 初始化时需要递归遍历所有属性,转换为响应式,性能开销与数据大小成正比。 | 惰性劫持:只在真正访问某个属性时才会对其进行递归劫持,初始化性能大幅提升。 |
代码示例 | javascript data() { return { obj: { a: 1 } } }, mounted() { this.obj.b = 2; // **不是响应式的!** this.$set(this.obj, 'b', 2); // 必须是响应式的 } | javascript const state = reactive({ a: 1 }); state.b = 2; // **直接是响应式的!** |
结论: Vue 3 的 Proxy
实现了真正的全功能响应式,开发者心智负担更小,性能更好。
2. API 风格:Options API vs. Composition API
这是开发者最能直观感受到的变化。
Vue 2: Options API
<template><div><p>{{ count }} * 2 = {{ doubleCount }}</p><button @click="increment">Increment</button><p>User: {{ userName }}</p></div>
</template><script>
export default {// Data选项data() {return {count: 0,user: {name: 'Alice'}};},// Computed选项computed: {doubleCount() {return this.count * 2;},userName() {return this.user.name;}},// Methods选项methods: {increment() {this.count++;}},// 生命周期钩子mounted() {console.log('Component mounted');}
};
</script>
优点: 结构清晰,强制按照选项类型组织代码,对新手非常友好。
缺点: 逻辑关注点分离。一个功能的代码(如“用户信息”)被分散在 data
, computed
, methods
, mounted
等不同的选项中。阅读和维护一个复杂功能时,需要在代码中反复上下滚动。
Vue 3: Composition API (主要推荐方式)
<template><!-- 与 Vue 2 模板语法几乎一致 --><div><p>{{ count }} * 2 = {{ doubleCount }}</p><button @click="increment">Increment</button><p>User: {{ userName }}</p></div>
</template><script setup>
import { ref, computed, onMounted } from 'vue';// --- 计数器功能 ---
// 1. 使用 ref 定义响应式数据
const count = ref(0);
// 2. 使用 computed 定义计算属性
const doubleCount = computed(() => count.value * 2);
// 3. 定义方法
function increment() {count.value++;
}// --- 用户功能 ---
// 另一个逻辑关注点的代码可以组织在一起!
const user = ref({ name: 'Alice' });
const userName = computed(() => user.value.name);// 生命周期钩子
onMounted(() => {console.log('Component mounted');// 可以在这里初始化用户数据// fetchUser(...)
});// 逻辑可以轻松提取到独立的组合式函数中,实现极致复用!
// useCounter(), useUser() 等
</script>
优点:
- 更好的逻辑组织:可以将一个功能相关的所有代码(数据、计算属性、方法、生命周期)放在一起,而不是按选项类型分散。
- 极致的逻辑复用:可以轻松地将一组逻辑抽取到一个组合式函数 (Composable) 中,实现比 mixins 更强大、更清晰的跨组件逻辑复用。
- 更好的 TypeScript 支持:全是变量和函数,类型推断非常自然。
注意: Vue 3 完全兼容 Options API,你可以根据项目或团队习惯选择使用。
3. 生命周期钩子变化
大部分钩子只是名称前加了 on
,并需要从 vue
中导入。beforeDestroy
和 destroyed
被更名为 onBeforeUnmount
和 onUnmounted
,语义更准确。
Vue 2 | Vue 3 (Composition API) | 说明 |
---|---|---|
beforeCreate | setup() 自身 | 不再需要,setup() 是第一个被调用的函数 |
created | setup() 自身 | 不再需要,setup() 是第一个被调用的函数 |
beforeMount | onBeforeMount | |
mounted | onMounted | |
beforeUpdate | onBeforeUpdate | |
updated | onUpdated | |
beforeDestroy | onBeforeUnmount | 名称更贴切 |
destroyed | onUnmounted | 名称更贴切 |
errorCaptured | onErrorCaptured |
4. 碎片化组件 (Fragment) 和 Teleport
- Vue 2: 每个组件必须有且仅有一个根元素。
<template><div> <!-- 必须的根元素 --><h1>Title</h1><p>Content</p></div> </template>
- Vue 3: 组件可以包含多个根元素。这简化了渲染结构。
<template><h1>Title</h1> <!-- 多个根元素 --><p>Content</p> </template>
- Teleport: Vue 3 新增的内置组件,可以将组件的一部分内容“传送”到 DOM 结构的其他位置(通常是
body
末尾),非常适合实现全局的 Modal、Toast、Dialog 等组件,解决样式和z-index
问题。<template><button @click="showModal = true">Show Modal</button><Teleport to="body"> <!-- 将模态框内容传送到body末尾 --><div v-if="showModal" class="modal"><p>Hello from the modal!</p><button @click="showModal = false">Close</button></div></Teleport> </template>
5. 性能优化
- Tree-shaking 支持:Vue 3 的很多 API(如
v-model
参数、transition
动画)都是按需导入的。如果你没有使用它们,它们最终不会被打包到生产环境中,从而减小项目体积。 - 编译时优化:
- Block tree:编译器会分析模板,生成更高效的虚拟 DOM。静态节点会被提升到渲染函数之外,下次
diff
时直接复用。 - Patch flag:在编译时给动态节点打上标记(如
1
代表文本内容变化,2
代表 class 变化),diff
算法时只需检查有标记的节点,大幅减少了虚拟 DOM 对比的开销。
- Block tree:编译器会分析模板,生成更高效的虚拟 DOM。静态节点会被提升到渲染函数之外,下次
6. 其他重要变化
方面 | Vue 2 | Vue 3 | 说明 |
---|---|---|---|
v-model | 一个组件上一个 v-model | 可多个 v-model ,如 v-model:title v-model:content | 更灵活的双向绑定 |
Key | 在 v-if /v-else 分支上建议使用 key | 强制要求 | 提高渲染正确性 |
异步组件 | const AsyncComp = () => import('./comp.vue') | 使用 defineAsyncComponent 辅助函数 | 功能更强,支持配置加载状态和错误组件 |
全局 API | Vue.component , Vue.directive | createApp(App).component(...).mount(...) | API 改为应用程序实例(app)方法,避免全局配置污染 |
总结与选择建议
Vue 2 | Vue 3 | |
---|---|---|
状态 | 维护期 (LTS),不再增加新特性 | 活跃开发,未来方向 |
优点 | 稳定、生态成熟、学习曲线平缓 | 性能卓越、逻辑复用能力强、TS支持完美、现代化 |
缺点 | 响应式系统有缺陷、TS支持弱、大型项目组织性差 | 需要学习新概念(Composition API)、生态过渡期 |
适用场景 | 维护现有老项目、团队不熟悉新特性、追求极致稳定 | 所有新项目、需要更好性能和代码组织、深度使用 TypeScript |
最终建议:
对于新项目,请毫不犹豫地选择 Vue 3。它代表了未来的方向,在性能、开发体验和长期维护性上都有巨大优势。对于现有的 Vue 2 项目,如果运行良好,不必急于重构,但可以开始尝试在部分新功能中使用 Composition API
(Vue 2.7 已支持),为未来升级做准备。