《uni-app开发Harmony Next平台的App》第八篇:vue2项目迁移到vue3——为鸿蒙化做准备
《uni-app开发Harmony Next平台的App》第八篇vue2项目迁移到vue3——为鸿蒙化做准备为什么要迁移到Vue3uni-app官方在HBuilderX 4.27版本之后对Harmony Next平台的App编译只支持Vue3。如果现有项目是Vue2构建的直接编译到鸿蒙会报错必须先将项目升级到Vue3。Vue3本身在性能、TypeScript支持、组合式API等方面都有明显提升。迁移后不仅能编译到鸿蒙还能获得更好的开发体验。但要注意迁移不只是改版本号那么简单Vue2和Vue3在语法、生命周期、响应式系统上都有重大变化。下面这篇文章会梳理出迁移过程中最核心的改动和踩坑点。环境说明项目版本HBuilderX4.27 及以上uni-app建议升级到最新正式版目标平台Harmony Next仅支持Vue3编译一、迁移前的准备在动手修改代码之前先做好这几件事备份项目复制一份旧项目避免操作失误。升级HBuilderX确保使用能编译鸿蒙的版本4.27。检查依赖项目用到的第三方插件如uView、colorUI等是否支持Vue3。不支持的需要找替代品或升级版本。清理无用代码删除已经废弃的写法比如Vue.prototype挂载全局方法。官方提供了一个迁移指南页面https://uniapp.dcloud.net.cn/tutorial/migration-to-vue3.html可以对照参考。二、核心差异与代码迁移2.1 响应式系统的变化Vue2使用data函数返回对象通过Object.defineProperty实现响应式。Vue3使用ref和reactive基于Proxy实现。迁移时最直观的改动!-- Vue2 Example.vue -- template view text{{ count }}/text button clickincrement1/button /view /template script export default { data() { return { count: 0 } }, methods: { increment() { this.count } } } /script改为Vue3的组合式API写法推荐!-- Vue3 Example.vue -- template view text{{ count }}/text button clickincrement1/button /view /template script setup import { ref } from vue const count ref(0) function increment() { count.value } /script如果不想用setup语法糖也可以保留选项式API保持兼容script import { ref } from vue export default { setup() { const count ref(0) const increment () { count.value } return { count, increment } } } /script注意在Vue3中data中的属性不能直接使用ref包裹必须通过setup()返回。而使用script setup后顶层的响应式变量会自动暴露给模板更简洁。2.2 生命周期的变化Vue2的生命周期函数在Vue3中大部分重命名并且需要在组合式API中使用对应的钩子。Vue2Vue3 (选项式)Vue3 (组合式)beforeCreatebeforeCreate不再需要由setup替代createdcreatedsetup()执行时机等同于createdbeforeMountbeforeMountonBeforeMountmountedmountedonMountedbeforeUpdatebeforeUpdateonBeforeUpdateupdatedupdatedonUpdatedbeforeDestroybeforeUnmountonBeforeUnmountdestroyedunmountedonUnmountederrorCapturederrorCapturedonErrorCaptured注意beforeDestroy和destroyed已被beforeUnmount和unmounted替代。迁移示例// Vue2exportdefault{mounted(){console.log(mounted)},beforeDestroy(){console.log(before destroy)}}// Vue3 选项式exportdefault{mounted(){console.log(mounted)},beforeUnmount(){console.log(before unmount)}}// Vue3 组合式script setupimport{onMounted,onBeforeUnmount}fromvueonMounted(()console.log(mounted))onBeforeUnmount(()console.log(before unmount))/script2.3 模板指令的细微变化v-modelVue3中v-model的默认修饰符和属性名有所调整。对于自定义组件v-model默认传递给modelValuepropinput事件改为update:modelValue。如果组件中使用了model选项改造v-model在Vue3中需要改为modelValueemit(update:modelValue)。v-if与v-show行为没有变化但需要注意在Vue3中v-if的优先级略高于v-for不会出现Vue2中的作用域冲突但也不建议同时使用。keykey的使用方式不变但Vue3对同级的动态节点优化更好。自定义指令Vue3的自定义指令生命周期钩子名称发生了变化例如bind→beforeMountinserted→mounted等。uni-app中很少自定义指令如果使用了需要查阅文档修改。2.4 全局API的变化Vue.prototype→app.config.globalPropertiesVue.nextTick→ 从vue单独导入Vue.set/Vue.delete→ 不再需要因为响应式系统自动支持添加/删除属性Vue.extend→ 被移除组件定义改用函数式组件或defineComponent在uni-app中如果使用了Vue.prototype挂载全局方法比如this.$api需要在main.js中修改// Vue2Vue.prototype.$api{...}// Vue3import{createSSRApp}fromvueconstappcreateSSRApp(App)app.config.globalProperties.$api{...}注意uni-app实际上使用createApp而不是createSSRApp在HBuilderX自动生成的模板中已经是Vue3版本。2.5 过滤器的移除Vue3移除了过滤器filter。如果项目中使用了过滤器需要替换为methods或computed。迁移示例!-- Vue2 --text{{ price | currency }}/text改为!-- Vue3使用computed --text{{ currencyPrice }}/textscript setupimport{computed}fromvueconstpropsdefineProps({price:Number})constcurrencyPricecomputed(()${props.price.toFixed(2)})/script三、使用迁移构建工具uni-app官方提供了一键迁移的功能实际上在HBuilderX中当打开一个Vue2项目时编辑器会提示“此项目为Vue2建议升级到Vue3”。但并没有全自动转换工具需要手动修改。建议操作流程在HBuilderX中新建一个Vue3项目模板。将旧项目的pages、components等文件夹复制过来。逐个修改.vue文件将script改写为组合式API。修改main.js、App.vue、manifest.json等根文件。升级依赖将manifest.json中的vueVersion改为3如果有并且在package.json如果存在中安装Vue3相关包。实际上uni-app的Vue3项目不需要显式安装vue包HBuilderX内置了。但某些第三方插件可能需要手动更换版本。四、踩坑记录迁移过程中常见问题问题1uni-app内置组件在Vue3中不显示现象把Vue2项目代码复制到Vue3模板后页面空白控制台报错说scroll-view等组件未注册。原因Vue3要求组件必须先注册才能使用。而旧版uni-app的Vue2项目会把内置组件自动注册但Vue3项目中需要显式引入或者检查manifest.json中是否包含easycom配置。如果使用了easycom模式需要确保组件名称匹配。解决方案在pages.json中添加easycom配置或者确保组件在components目录下且命名符合规范。最简单的方法是检查HBuilderX生成的新项目模板中的pages.json复制其easycom配置。// pages.jsoneasycom:{autoscan:true,custom:{^uni-(.*):/components/uni-$1/uni-$1.vue}}问题2this.$mp等内部属性无法使用现象Vue2项目中使用了this.$mp获取小程序平台信息迁移后该属性为undefined。原因Vue3中uni-app的内部属性有所调整。$mp在Vue3中可能改为其他方式获取或者需要使用getEnv()函数。解决方案使用uni-app提供的uni.getSystemInfo或uni.getLaunchOptionsSync等标准API避免直接访问$mp。如果非用不可可以改为从Vue.prototype挂载对象中读取。问题3reqires在Vue3中不能使用模块加载现象require(/utils/xxx.js)在Vue3中报错提示require未定义。原因Vue3全面拥抱ES Module不支持CommonJS的require。HBuilderX在Vue3项目中默认使用ES Module需要改用import。解决方案将所有require改为import。注意动态导入也要使用await import()。// Vue2constutilrequire(/utils/util.js)// Vue3importutilfrom/utils/util.js问题4slot-scope指令无效现象旧项目中使用了template slot-scopescope迁移后作用域插槽不渲染。原因Vue3已废弃slot-scope改用v-slot指令。解决方案将slot-scope替换为v-slot。!-- Vue2 --templateslot-scope{item}.../template!-- Vue3 --templatev-slot{item}.../template!-- 简写 --template#default{item}.../template问题5uni-组件库需要升级很多第三方组件库如uView、colorUI的Vue2版本不能在Vue3项目中使用需要升级到对应的Vue3版本或改用uni-app官方插件。如果在HBuilderX插件市场搜索不到Vue3版本建议更换为uni-ui官方组件库支持Vue3。五、最佳实践先在Vue3环境下编译小程序端验证鸿蒙模拟器启动较慢可以先编译到微信小程序工具或H5端确认基础功能正常后再编译鸿蒙。这样能更快定位问题。逐步迁移不要一次改完建议按页面顺序逐个修改每次只改几个文件编译测试确保不引入新错误。保留选项式API作为过渡如果团队不熟悉组合式API可以继续使用选项式APIexport default { data(), methods... }Vue3完全兼容。但注意生命周期的名称变化和Vue.prototype的替换。使用TypeScriptVue3对TS支持更友好迁移时可以顺便引入TypeScript提高代码质量。只需将script改为script langts安装types/uni-app等类型包。检查异步组件引用Vue3对异步组件的定义方式变了使用defineAsyncComponent如果项目中有动态组件加载需要按新写法调整。六、完整项目结构示例下面是一个迁移后的H5页面示例包含组合式API、生命周期和状态管理。pages/index/index.vue:template view classindex text classtitle{{ msg }}/text button clickupdate更新/button person-detail refchildRef / /view /template script setup import { ref, onMounted, onUnmounted } from vue import PersonDetail from ./personDetail.vue const msg ref(Hello Harmony Next) const childRef ref(null) function update() { msg.value 更新于 ${new Date().toLocaleTimeString()} // 调用子组件方法 childRef.value?.doSomething() } onMounted(() { uni.showToast({ title: 页面加载完成 }) }) onUnmounted(() { console.log(页面销毁) }) /scriptpages/index/personDetail.vue:template view text姓名{{ name }}/text text年龄{{ age }}/text /view /template script setup import { ref } from vue const name ref(张三) const age ref(25) function doSomething() { age.value } // 暴露方法给父组件 defineExpose({ doSomething }) /scriptFAQQ迁移后编译到H5没问题但鸿蒙模拟器报错“ReferenceError: require is not defined”A项目中还有文件使用了require比如在static下的某些库需要全局搜索替换为import。Q原来用uni.$emit全局通信迁移后怎么用AVue3中uni.$emit一样可以用它是uni-app的API不受Vue版本影响。但最佳实践推荐使用vue的provide/inject或状态管理库pinia。Q有些第三方uni-app插件在Vue3下无法安装A检查插件市场是否有Vue3版本标签为vue3如果没有可能需要手动fork后适配。建议先替换为官方uni-ui组件。Q迁移后部分页面可能访问未定义变量如何快速定位A启用Vue3的模板编译警告在main.js中加入app.config.warnHandler (msg) console.warn(msg)能打印出更详细的错误信息。如果你在迁移过程中遇到其他问题欢迎留言讨论。最后一步编译到鸿蒙验证所有功能正常。