1. 响应式系统的变化
-
问题 :Vue3 使用
Proxy
替代Object.defineProperty
,导致部分 Vue2 的响应式写法失效。 -
解析 :
-
数组直接索引修改 :
javascript// Vue2:需使用 Vue.set 或 splice this.$set(this.items, 0, 'new value'); this.items.splice(0, 1, 'new value'); // Vue3:Proxy 支持直接索引修改(但需注意 reactive 包裹的数组) const items = reactive(['old value']); items[0] = 'new value'; // 直接生效
-
对象新增属性 :
javascript// Vue2:需使用 Vue.set this.$set(this.user, 'age', 25); // Vue3:直接赋值即可 const user = reactive({ name: 'Alice' }); user.age = 25; // 自动触发更新
-
-
修复 :使用
reactive()
或ref()
包裹数据,避免直接操作原始对象。
2. Options API 与 Composition API 的差异
-
问题:Vue3 推荐使用 Composition API,但旧项目可能依赖 Options API。
-
解析 :
-
生命周期钩子重命名 :
javascript// Vue2 export default { beforeDestroy() {}, destroyed() {} } // Vue3 import { onBeforeUnmount, onUnmounted } from 'vue'; export default { setup() { onBeforeUnmount(() => { /* ... */ }); onUnmounted(() => { /* ... */ }); } }
-
this
上下文变化 :javascript// Vue2:通过 this 访问 props export default { props: ['message'], methods: { showMessage() { console.log(this.message); } } } // Vue3:通过 setup 参数获取 props 和 context export default { props: ['message'], setup(props, { emit }) { const showMessage = () => { console.log(props.message); emit('custom-event'); }; return { showMessage }; } }
-
-
修复 :逐步重构复杂组件到 Composition API,例如将逻辑拆分为可复用的
useXxx
函数。
3. 全局 API 变更
-
问题 :Vue3 全局 API(如
Vue.nextTick
、Vue.directive
)改为模块导入。 -
解析 :
javascript// Vue2:全局 API Vue.filter('currency', value => `$${value}`); Vue.directive('focus', { inserted: el => el.focus() }); // Vue3:模块导入 + app 实例 import { createApp } from 'vue'; const app = createApp({}); app.config.globalProperties.$filters = { currency: v => `$${v}` }; app.directive('focus', { mounted: el => el.focus() });
-
修复 :使用
app.config.globalProperties
替代全局属性,并通过provide/inject
实现跨组件通信。
4. 模板语法变更
-
问题:模板中的部分语法行为变化。
-
解析 :
-
v-model
重构 :vue<!-- Vue2:默认绑定 value 和 input --> <ChildComponent v-model="title" /> <!-- Vue3:默认绑定 modelValue 和 update:modelValue --> <ChildComponent v-model:title="pageTitle" />
-
事件总线替代方案 :
javascript// Vue2:事件总线 const bus = new Vue(); bus.$on('event', handler); bus.$emit('event', data); // Vue3:使用 mitt import mitt from 'mitt'; const emitter = mitt(); emitter.on('event', handler); emitter.emit('event', data);
-
key
属性优先级 :vue<!-- Vue3:v-if/else 分支需显式指定 key --> <div v-if="show" key="a">Content A</div> <div v-else key="b">Content B</div>
-
-
修复 :检查模板中所有
v-model
和事件监听,更新为 Vue3 语法。
5. 第三方库兼容性
-
问题:Vue2 插件需升级到 Vue3 版本。
-
解析 :
-
Vue Router v4 示例 :
javascript// Vue2 import VueRouter from 'vue-router'; const router = new VueRouter({ routes }); // Vue3 import { createRouter, createWebHistory } from 'vue-router'; const router = createRouter({ history: createWebHistory(), routes });
-
Pinia 状态管理 :
javascript// stores/counter.js import { defineStore } from 'pinia'; export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++ } } }); // 组件中使用 import { useCounterStore } from './stores/counter'; const counter = useCounterStore(); counter.increment();
-
-
修复:优先迁移到官方推荐的替代库(如 Pinia)。
6. 构建工具迁移
-
问题:Vue CLI 项目需迁移到 Vite。
-
解析 :
-
Vite 配置文件示例 :
javascript// vite.config.js import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [vue()], publicPath: process.env.NODE_ENV === 'production' ? '/dist/' : '/' });
-
环境变量变更 :
textVue CLI 的 VUE_APP_* → Vite 的 VITE_*
-
-
修复 :使用
vite-plugin-vue2
暂存迁移,逐步升级到 Vue3。
7. 其他常见问题
-
Fragment 支持与 CSS 作用域 :
vue<!-- Vue3:多根组件可能导致样式泄漏 --> <template> <header>...</header> <main class="content">...</main> <!-- 父组件的 .content 可能影响子组件 --> </template>
-
<transition>
类名变更 :css/* Vue2 */ .v-enter { /* ... */ } /* Vue3 */ .v-enter-from { /* ... */ }
迁移策略建议
-
逐步升级依赖 :
bash# 升级 Vue2 到最新 2.7.x(支持部分 Vue3 特性) npm install vue@^2.7.0 # 使用 Vue3 迁移构建工具检测问题 vue add vue-next
-
自动化修复工具 :
- 运行
vue-cli-service upgrade
自动修复部分 API 变更。 - 使用 ESLint 插件
eslint-plugin-vue
检测废弃语法。
- 运行
-
混合开发模式 :
- 使用
vue-demi
库编写同时支持 Vue2/Vue3 的组件。
- 使用
通过结合具体案例和渐进式策略,开发者可显著降低迁移风险。完整迁移指南请参考 Vue3 官方文档。