
摘要Vue2 已于2023年底停止维护不少企业中后台项目都需要向Vue3迁移。本文站在业务开发视角不讲太多底层理论聚焦开发改造时会遇到的语法修改、模板报错、API废弃、组件行为变化、第三方组件兼容、调试排坑附带可直接复制的代码示例。如果你正在动手做Vue2转Vue3的页面改造这篇文章可以帮你快速定位问题。目录一、迁移前开发准备二、全局API改造上手第一个大坑三、模板语法变化四、v-model 语法改动五、生命周期变更重点警惕内存泄漏六、响应式API变化OptionsAPI / CompositionAPI七、组件通信事件总线 $(on/)$off/$once 移除八、插槽slot写法变更九、过滤器、mixin 废弃与替代方案十、UI库迁移ElementUI → ElementPlus 开发踩坑十一、工程构建层面改造要点十二、开发阶段高频隐性Bug十三、开发提效小技巧总结一、迁移前开发准备正式改代码前先做依赖盘点检查项目所有第三方包富文本、图表、PDF预览、自定义指令、埋点、弹窗组件确认是否存在Vue3版本。很多老旧包没有Vue3支持需要提前寻找替代库。确定迁移策略渐进迁移使用vue/compat兼容包Vue3环境兼容Vue2 OptionsAPI页面逐个改造适合大型项目适合业务团队逐步开发迭代。全量重构新建ViteVue3项目页面逐个重写适合小型项目。注意vue/compat只是过渡方案不能长期在线上保留后续需要逐步移除。二、全局API改造上手第一个大坑Vue2 是修改Vue全局构造函数Vue3 使用createApp创建独立应用实例不再污染全局。// Vue2 写法 import Vue from vue import ElementUI from element-ui Vue.use(ElementUI) Vue.prototype.$axios axios Vue.prototype.$msgbox Vue.prototype.$message // Vue3 改造后 import { createApp } from vue import ElementPlus from element-plus import axios from axios const app createApp(App) app.use(ElementPlus) // 挂载全局实例属性 app.config.globalProperties.$axios axios app.mount(#app)开发坑点老项目大量使用this.$xxx全局方法升级后全部失效需要统一迁移到globalPropertiesVue2的Vue.directive、Vue.filter、Vue.component全局注册全部改为app.directive/app.component。三、模板语法变化1. 根节点Vue2组件模板允许多个根节点Vue3默认模板只能单个根元素。!-- Vue2 允许 -- template div标题/div p内容/p /template !-- Vue3 需要改成单个根或者使用Fragment -- template !-- 直接写多个根也可以Vue3支持多根但是推荐理解差异 -- div标题/div p内容/p /templateVue3 支持多根节点但是多根模板不能使用ref自动继承开发时容易踩坑。2. 移除v-on.nativeVue2 给自定义组件绑定原生事件需要加.native修饰符Vue3直接移除该修饰符。!-- Vue2 -- MyComponent click.nativehandleClick/ !-- Vue3直接写即可 -- MyComponent clickhandleClick/四、v-model 语法改动Vue2 中一个组件只能绑定单个v-model本质是value属性 input事件。 Vue3单个v-model默认变成modelValueupdate:modelValue支持多个v-model!-- Vue2 -- CustomInput v-modelform.name/ !-- 等价于 -- CustomInput :valueform.name inputform.name $event/ !-- Vue3 -- CustomInput v-modelform.name/ !-- 等价于 -- CustomInput :modelValueform.name update:modelValueform.name $event/ !-- Vue3 多v-model示例 -- CustomInput v-model:nameform.name v-model:ageform.age/开发高频坑封装的业务组件如果自定义v-model升级后双向绑定直接失效必须修改组件内部prop和emit事件名称。五、生命周期变更重点警惕内存泄漏OptionsAPI 生命周期映射Vue2Vue3 OptionsAPICompositionAPI setupbeforeCreatebeforeCreatesetupcreatedcreatedsetupbeforeMountbeforeMountonBeforeMountmountedmountedonMountedbeforeUpdatebeforeUpdateonBeforeUpdateupdatedupdatedonUpdatedbeforeDestroybeforeUnmountonBeforeUnmountdestroyedunmountedonUnmounted⚠️ 最容易漏掉的坑beforeDestroy/destroyed被重命名。老代码如果不改名字定时器、SSE连接、事件监听不会执行销毁逻辑造成严重内存泄漏。CompositionAPI示例import { onMounted, onUnmounted } from vue onMounted(() { // 页面挂载开启定时器、SSE、订阅 }) onUnmounted(() { // 组件销毁清理资源 })六、响应式API变化OptionsAPI / CompositionAPIVue2Object.definePropertyVue3Proxy。 OptionsAPI写法大部分可以保留新增CompositionAPIref、reactive。import { ref, reactive, toRefs } from vue // ref基础类型 const count ref(0) console.log(count.value) // reactive对象、数组 const state reactive({ name: 张三 }) // ❌ 错误直接覆盖reactive对象响应式丢失 state { name: 李四 } // ✅ 正确修改属性 state.name 李四 // ❌ 解构直接丢失响应式 const { name } state // ✅ 使用toRefs保留响应式 const { name } toRefs(state)开发踩坑很多同学刚上手直接解构reactive页面数据不更新排查很久。七、组件通信事件总线 $(on/)$off/$once 移除Vue2常用new Vue()作为事件总线跨组件通信Vue3直接移除实例方法$on、$off、$once。✅ 推荐替代方案简单场景mitt轻量事件库import mitt from mitt const emitter mitt() // 发送 emitter.emit(refreshList, data) // 监听 emitter.on(refreshList, (data) {}) // 取消监听 emitter.off(refreshList)复杂业务状态Pinia替代VuexVuex依然可用但官方推荐Pinia。八、插槽slot写法变更旧的slot语法废弃Vue2旧写法!-- Vue2 废弃语法Vue3不支持 -- my-component slotheader slot-scopescope/my-componentVue3统一使用v-slot语法!-- 默认插槽 -- MyComponent v-slotscope {{ scope.row }} /MyComponent !-- 简写 # -- MyComponent #defaultscope /MyComponent !-- 命名插槽 -- MyComponent #headerscope /MyComponent九、过滤器、mixin 废弃与替代方案过滤器 filter 被移除Vue2模板内{{ value | formatDate }}过滤器Vue3不再支持。替代方案全局工具函数 / 计算属性computedmixin 不推荐继续大量使用 Vue3依然支持mixin但是存在命名冲突、来源不清晰等问题。新业务推荐CompositionAPI 抽离组合式函数useXxx替代mixin。十、UI库迁移ElementUI → ElementPlus 开发踩坑这是中后台项目改造工作量最大的一块开发高频坑组件事件变更很多组件事件由change改为update:xxx组件属性重命名比如size、type部分参数变更弹窗this.$message、this.$confirm调用方式变化// Vue2 ElementUI this.$message.success(操作成功) // Vue3 ElementPlus import { ElMessage } from element-plus ElMessage.success(操作成功)图标ElementPlus图标单独包不再内置需要单独引入element-plus/icons-vue这是升级后页面图标全部消失最常见原因。十一、工程构建层面改造要点Webpack迁移Vite推荐 Vite开发启动速度远快于webpack但是部分老webpack插件不兼容需要替换。如使用vue/compat兼容模式 需要在webpack/vite配置开启兼容标记允许Vue2 OptionsAPI运行。注意兼容模式会带来额外性能开销只能作为过渡。十二、开发阶段高频隐性Bug获取DOMthis.$refs.xxx在多根模板中ref行为变化watch监听Vue3 watch监听reactive对象获取旧值和Vue2行为有差异数组操作虽然Proxy解决下标响应问题但开发时依然要注意业务逻辑异步组件Vue2Vue.component异步写法废弃Vue3使用defineAsyncComponent依赖版本冲突升级后vue、vue-router、vuex/pinia版本需要配套升级。十三、开发提效小技巧优先改造公共组件先把全局组件、业务基础组件升级业务页面后改开启ESLint规则提前捕获语法错误页面改造完成后重点测试销毁逻辑定时器、订阅、SSE检查内存泄漏新旧页面共存模式路由分开改造完的页面单独上线灰度验证。总结从Vue2升级Vue3语法改动只是表层问题更多隐性bug藏在组件通信、资源销毁、第三方UI库、双向绑定上。 如果项目很大不要一次性全量重写。采用公共组件先行页面逐个迁移的策略一边迭代业务一边改造。 OptionsAPI可以继续保留用于旧页面新页面推荐直接上CompositionAPI逐步积累组合式函数提升代码复用能力。 Vue3的多根节点、Proxy响应式、v-model多绑定等特性长期来看能简化很多业务开发场景。