vue2项目升级至vue3(vue3+vite+ts)

本文指导如何将基于vue2、webpack和element-ui的项目升级到vue3、vite、element-plus和typescript,涉及版本更新、配置修改、API调整和组件替换等内容,确保项目在Vue3框架上正常运行。

前言

为保证vue2项目更高效地迁到vue3上,因此本次的升级,vue2的选项式API和js写法保持不变。只升级框架、组件和一系列插件,对升级的这部分与vue2原来项目不兼容的写法做出修改,来保证项目在vue3框架上正常运行。

由于Vue3 的组件可以按两种不同的风格书写:选项式 API 和组合式 API。而Vue2是按照选项式 API 写法来写的。为了更快更准确的将vue2项目升级至vue3,因此在本次的升级中代码结构保持不变,后续新写的页面再可以采用组合式API的写法。

本次框架升级还加了typeScript,但由于之前vue2项目还是用js写的,因此这一部分也保持不变,后续新写的页面再可以用ts。

于是乎:

本次升级的目的就是为了将原来的vue2+webpack+element-ui升级替换为vue3+vite+element-plus+ts,做整体框架的升级优化,然后项目可以正常跑起来,不报错。

了解完之后就开始干吧~~~

第一步:升级node、vue等

 1、查看node、vue版本,vue3要求node版本至少要在v18.3

关于node升级,大家可以去看这篇文章,安装nvm可以针对不同版本的项目选择对应的node版本,这样就会方便很多:nvm安装可切换不同版本nodejs_windows电脑nvm安装多版本nodejs-CSDN博客

第二步:创建项目框架

基础的项目框架搭建,可以先去这个链接:

vue3+vite+typeScript+vueRouter+vuex+axios+element-plus搭建项目框架_vue3搭建框架-CSDN博客

npm init vite@latest

1、按照命令进入项目文件中,安装包

cd vue3-vite-ts2
cnpm install

2、安装原先项目所有的插件

这里把原来的element-ui换成element-plus

//axios
cnpm install axios qs vue-router vuex --save

//sass
cnpm install sass --save-dev

//echarts element-plus @element-plus/icons moment nprogress normalize.css qs
cnpm install echarts element-plus @element-plus/icons moment nprogress normalize.css qs --save

 第三步:修改配置文件及vue全局api

1、配置打包环境,最终package.json文件:

{
  "name": "vue3-vite-ts2",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite --mode development",
    "test": "vite --mode test",
    "prod": "vite --mode production",
    "build:dev": "vite build --mode development",
    "build:test": "vite build --mode test",
    "build:prod": "vite build --mode production",
    "preview": "vite preview"
  },
  "dependencies": {
    "@element-plus/icons": "^0.0.11",
    "axios": "^1.4.0",
    "echarts": "^5.4.3",
    "element-plus": "^2.3.9",
    "moment": "^2.29.4",
    "normalize.css": "^8.0.1",
    "nprogress": "^0.2.0",
    "qs": "^6.11.2",
    "vue": "^3.3.4",
    "vue-router": "^4.2.4",
    "vuex": "^4.1.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.2.3",
    "sass": "^1.74.1",
    "typescript": "^5.0.2",
    "vite": "^4.4.5",
    "vue-tsc": "^1.8.5"
  }
}

创建三个文件,分别为开发(development)、测试(test)、正式(production)三个打包环境文件,与原来vue2写法是不一样的,vue3写法:

 注意:获取环境配置的方法也变了,记得全局搜索,全局替换:

process.env.VITE_APP_baseUrl 换成 import.meta.env.VITE_APP_baseUrl

2、修改 vite.config.ts 配置文件:

添加配置别名@,添加请求接口代理,添加打包优化

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: { // 配置别名
      '@': path.resolve(__dirname, './src')
    }
  },
  server: {
    open: true,
    host: 'localhost',
    port: 9000,
    hmr: { overlay: false },
    proxy: {
      '/basePath': {
        target: '你的ip',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/basePath/, ''),
      }
    },
  },
  build: {
    rollupOptions: {
      output: {
        chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
        entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
        assetFileNames: '[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
        // 最小化拆分包 node_modules的包逐个打包 将需要分离的包单独的打包出来
        manualChunks(id) {
          if (id.includes('node_modules')) {
            return id.toString().split('node_modules/')[1].split('/')[0].toString();
          }
        }
      }
    }
  }
})
//tsconfig.json文件里:

"compilerOptions": {
...
"baseUrl": ".",
    "paths": {
       "@/*":["src/*"],
     },
}

3、开始修改文件啦,把之前的代码都移植过来,包括src里面的直接拷过来

1)main.ts文件:

Vue2使用全局API来注册插件、混入、指令等,即通过Vue.use、Vue.mixin、Vue.directive等方法。这种方式有一些问题,比如可能造成命名冲突,也不利于模块化和按需加载。

Vue3使用局部API来注册插件、混入、指令等,即通过createApp方法创建一个应用实例,然后通过app.use、app.mixin、app.directive等方法。这种方式可以避免全局污染,也更符合模块化的思想。 

 按照下面这个对全局的api修改:

Vue.use 替换为:app.use

Vue.prototype 替换为: app.config.globalProperties

Vue.component 替换为: app.component

一通改。。。

有些需要特别改动的比较费事的先注掉,比如自定义指令,自定义组件等,等项目先跑起来,后面再慢慢改。

2)、有引用 element-ui 的替换成 element-plus

import { message, messageBox } from 'element-ui' 替换为

import { ElMessage, ElMessageBox } from 'element-plus'

改完后的main.ts文件:

import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
//
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import '../theme/index.css'
import './fonts/iconfont.css'
//ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//el-icon
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}
app.use(ElementPlus)
//router
import router from './router'
app.use(router)
//store
import store from './vuex/index'
app.use(store)
// axios
import axios from './axios/api'
import '@/axios/permission'
// websocket
import wsConnection from '@/axios/websocket.js'
app.config.globalProperties.$setWs = wsConnection
// //按钮权限
// import './utils/directives/install'
// import { hasBtnPermission } from './utils/directives/button/bthIsShowOrElse' // button permission
// app.config.globalProperties.hasPerm = hasBtnPermission
//loading 全局加载
import loading from './components/common/loading/loading.js' // 引入loading
app.use(loading) // 全局使用loading
// message 全局提示框
import message from './components/common/message/message.js'
app.config.globalProperties.$messageBlock = message
// moment 全局时间处理
import moment from 'moment'
app.config.globalProperties.$moment = moment
// myTooltip 全局文字溢出隐藏 hover显示文字提示
import myTooltip from '@/components/common/myTooltip/index.vue'
app.component('myTooltip', myTooltip) //全局自定义组件

app.mount('#app')

3)、vuex引入的index.js 也需要改

import { createStore } from 'vuex'
//
import getters from './getters'
import user from './modules/user'
import sidebar from './modules/sidebar'
//
const store = createStore({
  modules: {
    user,
    sidebar,
  },
  getters,
})

export default store

4)、router文件中的index.js也需要改

import { defineAsyncComponent } from 'vue';
import { createRouter, createWebHistory } from 'vue-router'

const index = defineAsyncComponent(() => import('@/pages/index.vue'))
// login
const superLogin = defineAsyncComponent(() => import('@/pages/login/superLogin.vue'))
//404
const notfonud404 = defineAsyncComponent(() => import('@/pages/error/404.vue'))

const routes = [
  {
    name: "superLogin",
    path: "/login",
    component: superLogin
  },
  {
    name: "404",
    path: '/404',
    component: notfonud404
  },
  {
    path: '/index',
    name: '首页',
    redirect: '',
    component: index,
    children: [

    ]
  },
  {
    // 匹配所有路径  vue2使用*   vue3使用/: pathMatch(.*)* 或 /: pathMatch(.*) 或 /: 
    catchAll(.*)
    path: '/:catchAll(.*)*',
    redirect: '/404',
  },
]
const router = createRouter({
  history: createWebHistory(),
  routes,
})
export default router

5)、app.vue文件 替换成你原来的文件 就行

6)、ok , npm run dev 启动项目吧,算是启起来了

接下来,开始更艰难的一步:一个页面一个页面的看着改吧:

第四步:一个页面一个页面过,一个一个问题改

1、插槽及图标修改

//vue2 element-ui写法:
<el-input name="mobile">
   <i slot="prefix" class="el-input__icon el-icon-mobile"></i>
</el-input>
<template slot="error" slot-scope="{ error }">
//
</template>


//vue3 element-plus写法:
<el-input name="mobile" >
  <template #prefix>
    <el-icon :size="16"><Iphone /></el-icon>
  </template>
</el-input>
<template #error="{ error }">
//
</template>

类似于这样的:

slot="prefix" 改成  #prefix

slot="error" slot-scope="{ error }"  改成  #error="{ error }"

全局所有的插槽要注意啦:

原来是可以直接在标签上写slot,现在不行了,必须写在 <template>标签上

(1)全局搜索 slot-scope="scope" 直接全局替换 成  #default="scope"

(2)全局搜索 slot="content" 逐个改成 <template #content>的写法

(3)全局搜索 slot="append" 逐个检查 替换成 <template #append>的写法

(4)全局搜索 slot="footer" 逐个检查 替换成 <template #footer>的写法

等等。。。一通改

2、el-menu菜单修改:

elsub-menu  改成 el-sub-menu,包括样式里classname中的

3、图片引入require报错:

换成import引入方式

4、主题色修改:

原来:element-ui采用主题色更换的方式是在线定制主题色工具,直接下载下来引入项目中

现在:element-plus没找到在线定制主题色工具,因此需要修改下:

然后在 vite.config.ts:全局引入sass定义的所有变量

preprocessorOptions: {
	// 全局sass变量引入
	scss:{
		additionalData: '@use "./src/assets/css/commonCss/globalVariate/index.scss" as *;',
	}
},

 至此主题色生效

项目中样式我分为两大类,一类是公共样式,公共样式里分为全局变量和公共需要的样式,一类是页面样式。

5、各种组件样式修改:

1)全局配置中文

2) el-dialog修改

 element-ui写法:

element-plus写法:

还有头部、脚部的插槽方式修改 

custom-class 也要弃用了,换成class:全局搜索,全局修改

3) el-pagination修改:

 element-ui写法:

element-plus写法:

4) el-descriptions修改:

 element-ui写法:

element-plus写法:

5) el-date-picker修改:

 element-ui写法:

以前这种写法,日期选择是可以正确显示的,但是现在老是只能显示选择的时间的1号,后来才发现是格式写的不对,全局改下

element-plus写法:

 

6) el-radio修改:

 element-ui写法:

element-plus写法:

6、$set报错:

直接改成正常的赋值写法就行 ,不用$set,vue3已经废弃$set啦

7、生命周期钩子函数修改:

Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名了,需要修改下:

beforeDestroy 改为  beforeUnmount

destroyed 改为  unmounted

8、过度类名的更改:

// vue2写法:
.v-enter,
.v-leave-to {
  opacity: 0;
}
.v-leave,
.v-enter-to {
  opacity: 1;
}


//vue3写法:
.v-enter-from,
.v-leave-to {
  opacity: 0;
}
.v-leave-from,
.v-enter-to {
  opacity: 1;
}

9、全局样式因为组件结构有变动,一个个修改

第五步:各种报错修改记录 

1、报错:Invalid VNode type: undefined (undefined)

在vue3中组件被多次注册就会报Invalid VNode type: undefined (undefined)的错,导致页面空白。 解决方式:引入 defineAsyncComponent 异步加载组件

import {defineAsyncComponent} from 'vue';
components: {
       you:defineAsyncComponent(()=>import('@/views/you.vue'))
},

全局搜索,全局修改

2、报错:[Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header.

render-header改成scoped-slot

全局搜索,全局修改

3、报错:type.text is about to be deprecated in version 3.0.0, please use link instead.

button按钮的type="text"要废弃,改成link 

全局搜索,全局修改

4、报错:Vue Router warn The “next“ callback was called more than once in one navigation guard

出现这个问题,检查next方法是不是写了两次 ,执行了两次,去掉一个

第六步:整理不兼容/新增特性等修改清单

官网vue3迁移地址:Vue 3 迁移指南

 两者作用于同一个元素上时,v-if 会拥有比 v-for 更高的优先级。

 v-on 的 .native 修饰符已被移除。

//Vue3

import { defineAsyncComponent } from 'vue'
const asyncModal = defineAsyncComponent(() => import('./Modal.vue'))
  • destroyed 生命周期选项被重命名为 unmounted
  • beforeDestroy 生命周期选项被重命名为 beforeUnmount

 过渡类名 v-enter 修改为 v-enter-from、过渡类名 v-leave 修改为 v-leave-from

被移除的 API

这里放一个别人写的修改清单,感觉清晰明了,觉得后面用的到:

Vue 2.x 项目升级到 Vue 3详细指南【修改清单】_vue2升级vue3-CSDN博客

 至此就结束啦,上面这些就是做升级做的一个笔记记录,最后就剩下一个页面一个页面测试检查,有问题再细改,到这里基本页面及操作都能正常,不会报错,就是还有一些警告,关于echarts的一些api废弃警告之类的,后面继续再改,有啥问题再继续记录,over~~~ 

2024-9-12记录:

好长时间没打开了,今天启动这个项目,直接报错:

 Cannot find module @rollup/rollup-win32-x64-msvc. npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). Please try `npm i` again after
 removing both package-lock.json and node_modules directory.

于是就按照提示 删除package-lock.json and node_modules,但是无用,最后还是看了这个博客,才解决问题。就是从新设置了下淘宝镜像源,不知道啥原因。记录下吧~~~

# Vite项目启动服务器时报错 Error: Cannot find module @rollup/rollup-win32-x64-msvc.(三种方法解决)_rollup.win32-x64-msvc.node-CSDN博客

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仰望半月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值