前言:Vue3 凭借更好的性能、Proxy 响应式、Composition API 以及完善的 TS 支持,已经成为前端主流版本。但很多同学在从 Vue2 迁移到 Vue3 时,总会因为 API 变化、语法差异踩各种坑。
本文整理了 Vue2 升级 Vue3 最核心的 5 个变化,搭配完整可运行代码案例,帮你一次性避开 90% 常见坑,无痛完成迁移。
一、API 风格巨变:Options API → Composition API
这是 Vue2 到 Vue3 最核心、最直观的区别。
1.1 核心区别
- Vue2 :按
data、methods、computed、watch分类写代码,逻辑容易分散。 - Vue3 :推荐使用 Composition API +
<script setup>,逻辑聚合、复用性更强、代码更简洁。
1.2 实战对比
Vue2 写法
vue
<template>
<div>
<input v-model="count" type="number" />
<button @click="addCount">加 1</button>
<p>双倍值:{{ doubleCount }}</p>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
computed: {
doubleCount() {
return this.count * 2
}
},
methods: {
addCount() {
this.count++
}
},
mounted() {
console.log('mounted', this.count)
}
}
</script>
Vue3 <script setup> 写法
vue
<template>
<div>
<input v-model="count" type="number" />
<button @click="addCount">加 1</button>
<p>双倍值:{{ doubleCount }}</p>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
// 响应式变量
const count = ref(0)
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 方法
const addCount = () => {
count.value++
}
// 生命周期
onMounted(() => {
console.log('mounted', count.value)
})
</script>
1.3 必避坑点
setup内部没有 this ,不能写this.xxxref变量在 JS 中必须用.value,模板中不用- 优先使用
<script setup>,代码量减少 50%
二、生命周期函数改名与调整
Vue3 对生命周期做了语义化优化,大部分只是换个名字。
2.1 对应关系表
| Vue2 生命周期 | Vue3 组合式 API | 说明 |
|---|---|---|
| beforeCreate | setup 内部 | 已合并 |
| created | setup 内部 | 已合并 |
| beforeMount | onBeforeMount | - |
| mounted | onMounted | - |
| beforeUpdate | onBeforeUpdate | - |
| updated | onUpdated | - |
| beforeDestroy | onBeforeUnmount | 改名 |
| destroyed | onUnmounted | 改名 |
2.2 避坑点
- 不要再写
beforeDestroy和destroyed,会直接失效 - 所有生命周期都需要从
vue中导入使用
三、全局 API 重构:不再污染全局 Vue
Vue2 全局操作容易污染,Vue3 改用 createApp 实例化应用。
3.1 Vue2 全局挂载
js
import Vue from 'vue'
import axios from 'axios'
Vue.prototype.$axios = axios
组件内使用:
js
this.$axios.get(...)
3.2 Vue3 标准写法(生产推荐)
main.js
js
import { createApp } from 'vue'
import App from './App.vue'
import axios from 'axios'
const app = createApp(App)
// 全局 provide
app.provide('$axios', axios)
app.mount('#app')
组件内使用:
js
import { inject } from 'vue'
const $axios = inject('$axios')
3.3 避坑点
- ❌ 不要用
Vue.prototype,Vue3 没有全局 Vue - ❌ 不要在生产用
getCurrentInstance,官方不推荐 - ✅ 全局共享优先使用
provide / inject或 Pinia
四、v-model 全面升级:更强大、更简洁
Vue2 的 v-model 本质是 value + input,Vue3 重新设计,支持多绑定。
4.1 Vue2 自定义 v-model
vue
<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
props: ['value']
}
</script>
4.2 Vue3 标准写法
vue
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
4.3 Vue3.4+ 超简写法(defineModel)
vue
<template>
<input v-model="model" />
</template>
<script setup>
import { defineModel } from 'vue'
const model = defineModel()
</script>
4.4 避坑点
- 自定义组件 v-model 不再用
value,改用modelValue - Vue2
.sync修饰符已废弃,直接用v-model:xxx - 支持多个 v-model 同时绑定
五、响应式原理升级:Object.defineProperty → Proxy
这是底层最大升级,解决了 Vue2 很多响应式缺陷。
5.1 Vue2 缺陷
- 无法监听数组下标修改
- 无法监听对象新增属性
- 必须用
this.$set / Vue.set
5.2 Vue3 天然支持
vue
<script setup>
import { reactive } from 'vue'
// 数组直接修改下标,依然响应
const list = reactive(['a', 'b', 'c'])
list[0] = 'hello'
// 对象新增属性,依然响应
const user = reactive({ name: '张三' })
user.age = 20
</script>
5.3 避坑点
- Vue3 不需要
$set,直接赋值即可 - 基本类型用
ref,对象/数组用reactive - 不要解构
reactive对象,会丢失响应式
六、Vue2 迁移 Vue3 实用工具
-
vue-codemod
官方批量转换工具,自动改语法:bashnpm install -g vue-codemod vue-codemod vue3-volar ./src -
Vue DevTools
必须使用 Vue3 专用版本 -
Vite 替代 Vue CLI,构建速度提升明显
七、总结(迁移速记版)
- 放弃 Options API,拥抱
<script setup> - 生命周期:
destroyed→onUnmounted - 全局挂载改用
app.provide或 Pinia - 自定义 v-model 改为
modelValue + update:modelValue - 响应式基于 Proxy,数组/对象直接修改即可
- 迁移先改小组件,逐步替换,风险更低
本文从实际项目迁移经验总结而来,覆盖绝大多数业务场景。如果你在迁移中遇到其他奇怪问题,欢迎在评论区交流!
版权声明:本文为原创技术博客,未经授权禁止转载、搬运、洗稿。如需转载请联系作者并注明原文出处。