当前位置: 首页 > news >正文

VUE2_TO_VITE_VUE3

Vue 2 项目迁移至 Vite + Vue 3 实战指南

项目背景

aiportal-ui原本是 Vue 2 项目,现在运行在Vite + Vue 3.5.34环境,但可以使用Vue 2 语法编写组件。


一、核心配置要点

1.1 vite.config.mjs - 启用 Options API

define:{__VUE_OPTIONS_API__:true,// ← 关键:启用 Vue 2 Options API 风格__VUE_PROD_DEVTOOLS__:false,},

原理:Vue 3 默认关闭 Options API,通过这个全局变量启用它。

1.2 package.json - 依赖版本

{"vue":"^3.5.34","view-ui-plus":"^1.3.24",// ← Vue 3 版本的 iView"element-plus":"^2.11.1","vuex":"^4.1.0",// ← Vue 3 版本的 Vuex"vue-router":"^4.5.1","mitt":"^3.0.1"// ← 替代 Vue 2 的 $bus}

二、兼容性实现三大机制

2.1 机制一:mitt 替代 $bus(事件总线)

文件src/main.js

importmittfrom"mitt";constemitter=mitt();constbus={$on:emitter.on,$off:emitter.off,$emit:emitter.emit,on:emitter.on,off:emitter.off,emit:emitter.emit,};// 挂载到全局app.config.globalProperties.$bus=bus;

使用方式(Vue 2 风格)

// 组件中直接使用this.$bus.$on('eventName',this.handler)this.$bus.$emit('eventName',data)this.$bus.$off('eventName',this.handler)

2.2 机制二:ui-compat.js(UI 组件兼容层)

文件src/plugins/ui-compat.js

import{h}from"vue";import{ElMessage,ElMessageBox,ElNotification}from"element-plus";// 将 Element Plus 的 API 适配成 Vue 2 风格exportconstMessage=(options)=>ElMessage(options);Message.success=(options)=>ElMessage.success(...);Message.warning=(options)=>ElMessage.warning(...);Message.error=(options)=>ElMessage.error(...);Message.info=(options)=>ElMessage.info(...);exportconstModal={info(options={}){...},confirm(options={}){...},};exportconstNotice={open(options){returnElNotification(options);},success(options){...},// ...};// 安装函数exportfunctioninstallUiCompat(app){app.config.globalProperties.$Message=Message;app.config.globalProperties.$Modal=Modal;app.config.globalProperties.$Notice=Notice;app.component("Icon",IconCompat);// 自定义 Icon 组件}

使用方式(Vue 2 风格)

this.$Message.success('操作成功')this.$Modal.confirm({content:'确定删除?'})this.$Notice.warning({content:'警告'})

2.3 机制三:view-ui-plus-ns.js(iView 组件兼容)

文件src/plugins/view-ui-plus-ns.js

import*asViewUIPlusfrom"view-ui-plus";functionisIViewAliasName(name){return/^i[A-Z]/.test(name);// 检测 i 前缀}functionremoveIViewPrefix(name){returnisIViewAliasName(name)?name.slice(1):name;}exportfunctioninstallViewUiPlusNs(app){Object.entries(ViewUIPlus).forEach(([,component])=>{// 自动注册:去除 i 前缀(如 iButton -> Button)constnormalizedName=removeIViewPrefix(name);app.component(normalizedName,component);});// 全局方法app.config.globalProperties.$Message=ViewUIPlus.Message;app.config.globalProperties.$Notice=ViewUIPlus.Notice;app.config.globalProperties.$Modal=ViewUIPlus.Modal;}

使用方式(Vue 2 风格)

<template><Button@click="handleClick">点击</Button><Breadcrumb><BreadcrumbItem>首页</BreadcrumbItem></Breadcrumb><Card>内容</Card></template>

三、main.js 完整初始化流程

import{createApp}from"vue";importElementPlusfrom"element-plus";importzhCnfrom"element-plus/es/locale/lang/zh-cn";import"element-plus/dist/index.css";import"view-ui-plus/dist/styles/viewuiplus.css";importmittfrom"mitt";importAppfrom"./App.vue";importrouterfrom"./router";importstorefrom"./store";import{installUiCompat}from"./plugins/ui-compat";import{installViewUiPlusNs}from"./plugins/view-ui-plus-ns";importi18nfrom"../i18n/index";constapp=createApp(App);// 1. Element Plus(Vue 3 组件库)app.use(ElementPlus,{locale:zhCn});// 2. 自定义兼容层(Message/Modal/Notice/Icon)installUiCompat(app);// 3. View UI Plus(Vue 3 版本的 iView)installViewUiPlusNs(app);// 4. Vuex(Vue 3 版本)app.use(store);// 5. Vue Routerapp.use(router);// 6. Vue I18napp.use(i18n);// 7. 全局混入会添加 handleError 方法app.mixin({methods:{handleError(msg,err){...}}});// 8. 事件总线constemitter=mitt();app.config.globalProperties.$bus={$on,$off,$emit,on,off,emit};// 9. 挂载app.mount("#app");

四、关键差异对比

特性Vue 2Vue 3 兼容方式
事件总线Vue.prototype.$busmitt+globalProperties
$MessageiView/Element UIui-compat.js适配层
$ModaliView/Element UIui-compat.js适配层
$NoticeiView/Element UIui-compat.js适配层
组件命名<i-Button>自动去除 i 前缀<Button>
VuexVuexvuex@4+app.use(store)
路由VueRouter@3vue-router@4

五、迁移检查清单

如果要将一个 Vue 2 项目迁移到 Vite + Vue 3:

  • package.json:升级vuevue-routervuex到 v4 版本
  • vite.config.mjs:添加define: { __VUE_OPTIONS_API__: true }
  • main.js:改用createApp()而非new Vue()
  • 事件总线:引入mitt替代$bus
  • Message/Modal/Notice:创建兼容层适配新组件库
  • Icon 组件:检查并创建兼容实现
  • [第三方组件库:确保使用 Vue 3 版本(如view-ui-plus而非iview

六、文档路径

  • 示例项目D:\benchmarkui\portal\aiportal-ui
  • 兼容层src/plugins/ui-compat.jssrc/plugins/view-ui-plus-ns.js
  • 入口文件src/main.js
  • 构建配置vite.config.mjs

七、核心配置要点

1.1 vite.config.mjs - 完整的

import{defineConfig}from"vite";importvuefrom"@vitejs/plugin-vue";importpathfrom"path";import{fileURLToPath}from"url";import{viteStaticCopy}from"vite-plugin-static-copy";importbasicSslfrom"@vitejs/plugin-basic-ssl";const__filename=fileURLToPath(import.meta.url);const__dirname=path.dirname(__filename);exportdefaultdefineConfig({plugins:[basicSsl(),vue({template:{},}),viteStaticCopy({targets:[{src:path.resolve(__dirname,"static/**/*"),dest:"static",},],}),],// @element-plus/icons-vue 预构建时会直接从 vue 内部 chunk 拉 defineComponent,// 绕过了 vue 入口的 init_runtime_dom,导致 isFunction 未初始化即调用 defineComponent。optimizeDeps:{exclude:["@element-plus/icons-vue"],},resolve:{extensions:[".mjs",".js",".ts",".jsx",".tsx",".json",".vue"],alias:{"@common":path.resolve(__dirname,"../common"),"@":path.resolve(__dirname,"src"),"@U":path.resolve(__dirname,"src/utils"),"@P":path.resolve(__dirname,"static"),uuid:path.resolve(__dirname,"node_modules/uuid/dist/index.js"),},},define:{__VUE_OPTIONS_API__:true,__VUE_PROD_DEVTOOLS__:false,},server:{host:"ai.test.huawei.com",port:8080,https:true,proxy:{"/rest":{target:"https://platform-dev.ai.test.huawei.com/",ws:false,changeOrigin:true,secure:false,},},},build:{outDir:path.resolve(__dirname,"public","html"),emptyOutDir:true,},});

原理:Vue 3 默认关闭 Options API,通过这个全局变量启用它。

package.json调用

{"name":"data-management-ui","version":"0.1.0","private":true,"type":"module","scripts":{"serve":"vite --mode development","serve-uat":"vite --mode uat","build-prd":"node --max_old_space_size=8192 node_modules/vite/bin/vite.js build --mode production","build-uat":"node --max_old_space_size=8192 node_modules/vite/bin/vite.js build --mode uat","build-beta":"node --max_old_space_size=8192 node_modules/vite/bin/vite.js build --mode beta","build-dev":"node --max_old_space_size=8192 node_modules/vite/bin/vite.js build --mode dev","lint":"eslint \"src/**/*.{js,vue}\" --fix","i18n:check":"node scripts/check-i18n-keys.mjs"},

http://www.jsqmd.com/news/908189/

相关文章:

  • 面试官:对话 Agent 上下文窗口不够用怎么办?
  • 从关键词到自然语言_AI搜索时代的搜索意图发生了哪些变化
  • 倾斜摄影测量全流程解析:从采集原理、CC建模到模型修复与土方计算
  • PS如何提高照片清晰度?3个方法零基础也能快速搞定高清修图
  • fselect:用类SQL语句查找文件
  • AI 告诉你代码安全,它在骗你!
  • Android init启动过程
  • 不只是VMware:开启AMD-V后,你的Win10/Win11还能玩转这些虚拟化工具
  • GPT5.5对Gemini3.5对DeepSeekV4编程能力横评
  • 别再死记硬背build.gradle了!用Groovy闭包和DSL思维,5分钟看懂Gradle配置的本质
  • 帆软报表FineReport连接Elasticsearch实战:从插件安装到SQL查询的保姆级避坑指南
  • 推荐几个博客
  • 用STM32F103 DIY一个JTAG边界扫描测试仪(附源码和避坑指南)
  • 别再只用洞洞板了!用嘉立创EDA+370电机,低成本搞定POV旋转LED全套硬件
  • AI与机器学习驱动的智能运营:从数据到决策的自动化闭环
  • 别再只盯着5G了!聊聊IMS:这个藏在通话、视频背后的‘老’技术,为啥现在又火了?
  • LLM生成Verilog代码的常见错误与修正技术
  • 保姆级教空间转录组分析| 01. 绪论
  • 【NCCL】transport数据传输(二)
  • 从5篇高温合金文章到16层协议:一个工业AI知识萃取的方法论
  • 用N32G031的TIM1驱动无刷电机:从寄存器配置互补PWM到死区时间实战避坑
  • SaaS未来趋势:AI融合、垂直化与生态化演进
  • 枚举三大应用场景
  • 别再只用BERT做分类了!用SentenceTransformers的5个实战场景(含代码)
  • Elasticsearch聚合分析实战
  • 火箭着陆制导算法:从凸优化到6-DoF控制
  • FreeRTOS性能调优利器:用SystemView揪出任务阻塞和中断延迟的元凶
  • 学习导师:从工具模式到感知模式的整合
  • LogAnalyzer实战:除了看系统日志,我这样用它监控Nginx访问和MySQL慢查询
  • Haskell与TensorFlow:用函数式编程构建安全可靠的AI系统