Vue 2 vs Vue 3:核心差异与优势解析
本文从架构、性能、开发体验、特性与工程化多个维度对比 Vue 2 与 Vue 3,并突出 Vue 3 的显著优势与迁移建议。
概览
- Vue 3 核心重写(Proxy 响应式 + 新编译器),显著提升性能与可维护性。
- Composition API 与
<script setup>提升逻辑组织、复用与类型体验。 - 更好的 Tree-Shaking、TypeScript 支持与生态(Vite、Pinia、SSR)。
架构与性能
- 响应式机制:
- Vue 2 使用
Object.defineProperty,对属性级拦截,不可检测新增/删除属性与索引变更;需Vue.set/$set补救。 - Vue 3 使用
Proxy,对对象级拦截,天然支持新增/删除属性、数组索引与Map/Set等数据结构。
- Vue 2 使用
- 依赖追踪:
- Vue 3 引入
effect与更细粒度的依赖图,减少不必要的重渲染。
- Vue 3 引入
- 编译优化:
- 静态提升、事件缓存、
patchFlag精确更新;大幅提高首屏与更新性能。
- 静态提升、事件缓存、
- 体积与 Tree-Shaking:
- Vue 3 模块化设计;未使用的功能在打包中可移除,减小 bundle。
- TS 支持:
- Vue 3 以 TS 编写,类型更完整;API 自带类型提示与推断。
// Vue 2 的响应式(简化示意)
const obj = { a: 1 }
// 新增属性需要 $set 才能响应
Vue.set(obj, 'b', 2)
// Vue 3 的响应式
import { reactive } from 'vue'
const state = reactive({ a: 1 })
state.b = 2 // 直接可响应
开发体验
- Composition API:
- 按逻辑分组而非选项分组,避免大型组件跨
data/methods/computed/watch跳转。 - 更易复用(抽取为可组合函数),更易测试与类型化。
- 按逻辑分组而非选项分组,避免大型组件跨
<script setup>:- 单文件组件更简洁,无需
export default;自动导出模板可用变量;编译期优化。
- 单文件组件更简洁,无需
- 更直观的生命周期与 watch:
onMounted/onUnmounted等组合式钩子;watchEffect和watch提供更灵活的副作用控制。
<!-- Vue 2:选项式 -->
<script>
export default {
data() { return { count: 0 } },
computed: { doubled() { return this.count * 2 } },
methods: { inc() { this.count++ } }
}
</script>
<!-- Vue 3:组合式 -->
<script setup>
import { ref, computed } from 'vue'
const count = ref(0)
const doubled = computed(() => count.value * 2)
const inc = () => { count.value++ }
</script>
新特性与能力
- 多根节点与 Fragment:
- Vue 3 支持组件返回多个根节点,减少不必要的包裹元素。
- Teleport:
- 在不改变组件逻辑的情况下,将子树渲染到任意 DOM 容器(如全局模态层)。
- Suspense:
- 更优雅地处理异步组件加载与占位内容。
- 新的
v-model语义:- 支持多
v-model、自定义模型名;modelValue与update:modelValue事件约定。
- 支持多
- Emits/Props 明确化:
emits显式声明事件,提高可读性与类型安全。
<!-- Teleport 示例 -->
<template>
<Teleport to="body">
<div class="modal">Hello</div>
</Teleport>
</template>
工程化与生态
- 创建与挂载:
- Vue 2:
new Vue({ render }).$mount('#app') - Vue 3:
createApp(App).use(router).mount('#app')
- Vue 2:
- 插件与全局 API:
- Vue 3 使用
app.use/app.component/app.directive,避免跨实例污染。
- Vue 3 使用
- 状态管理:
- 推荐使用 Pinia(更轻量、类型友好)替代 Vuex。
- 构建工具:
- 与 Vite 深度融合,快速冷启动、热更新与按需编译体验优异。
- SSR 与服务端能力:
- 新 SSR 渲染器、流式传输与更好并发支持。
// Vue 3 应用入口
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
迁移与兼容
- 渐进迁移:
- 可先将 Vue 2 升级到 2.7(支持部分 Composition API),再迁至 Vue 3。
- 迁移构建:
- 使用官方迁移构建捕捉弃用 API 与行为差异。
- 常见差异:
- 过滤器(filters)已移除;使用计算属性或方法替代。
v-on.native移除,使用emits或在根元素绑定。- 插槽与作用域插槽语法统一;
this上下文在组合式中不再使用。
实战对比示例
异步加载与副作用
<!-- Vue 2:选项式 -->
<script>
export default {
data() { return { user: null, loading: false, error: null } },
methods: {
async load() {
this.loading = true
try { this.user = await fetch('/api/user').then(r => r.json()) }
catch (e) { this.error = e }
finally { this.loading = false }
}
},
created() { this.load() }
}
</script>
<!-- Vue 3:组合式 + 更清晰副作用控制 -->
<script setup>
import { ref, onMounted } from 'vue'
const user = ref(null)
const loading = ref(false)
const error = ref(null)
const load = async () => {
loading.value = true
try { user.value = await fetch('/api/user').then(r => r.json()) }
catch (e) { error.value = e }
finally { loading.value = false }
}
onMounted(load)
</script>
逻辑复用(组合函数)
// Vue 3:抽取为可复用的 useFetch 组合函数
import { ref } from 'vue'
export function useFetch(url) {
const data = ref(null)
const loading = ref(false)
const error = ref(null)
const run = async () => {
loading.value = true
try { data.value = await fetch(url).then(r => r.json()) }
catch (e) { error.value = e }
finally { loading.value = false }
}
return { data, loading, error, run }
}
Vue 3 的关键优势总结
- 更快:编译优化与更细粒度更新,减少不必要渲染。
- 更小:模块化与 Tree-Shaking,减轻产物体积。
- 更强:Proxy 响应式、Teleport/Suspense/Fragment 等新能力。
- 更易维护:Composition API 与
<script setup>改善组织与复用。 - 更友好:一流的 TypeScript 支持与完善的 Devtools。
- 更现代:与 Vite/Pinia/SSR 生态深度融合,开发与部署体验优异。
迁移建议
- 优先在新增功能或重构模块中采用组合式写法与
<script setup>。 - 引入 Pinia 替代复杂的 Vuex 模块化方案,减少模板与样板代码。
- 结合 Vite 进行构建,获得更快的开发与构建速度。
- 使用官方迁移工具定位不兼容点,逐步替换弃用 API。
结论:在性能、可维护性与生态支持方面,Vue 3 全面优于 Vue 2,值得作为新项目与迁移目标的首选。
💬 评论