Vue 2 升级 Vue 3 全流程实战手册(Vue CLI 转 Vite + Element Plus + Pinia)

本文为Vue 2 项目迁移 Vue 3完整实战文档,包含依赖升级、构建工具切换、组件适配、样式改造、状态管理替换全流程,已脱敏处理隐私信息,可直接用于企业项目升级参考


📋 项目基础信息

表格

项目名称 XX 业务管理系统
升级日期 2026-04-18
原始版本 Vue 2.7.15 + Vue CLI + Element UI
目标版本 Vue 3.4.0 + Vite + Element Plus + TypeScript
升级状态 ✅ 已完成

一、技术栈对比

表格

组件 升级前 升级后 变化说明
核心框架 Vue 2.7.15 Vue 3.4.0 全面采用 Composition API,响应式系统基于 Proxy 重构,性能提升 30%-200%
路由管理 Vue Router 3.6.5 Vue Router 4.2.0 API 函数化,支持动态路由更灵活,移除部分旧 API
状态管理 Vuex 3.6.2 Pinia 2.1.7 Vue 3 官方推荐,无 mutations,TypeScript 支持更好,代码更简洁
UI 组件库 Element UI 2.15.13 Element Plus 2.4.4 适配 Vue 3,组件 API 优化,新增暗黑模式等特性
构建工具 Vue CLI 5.x Vite 5.0.0 基于 ESBuild 的极速开发体验,冷启动快 10 倍以上,热更新毫秒级
开发语言 JavaScript JavaScript + TypeScript 增强类型安全,减少运行时错误,提升代码可维护性

二、升级前准备工作

2.1 代码备份与环境检查

  1. 备份代码:将当前项目代码提交到 Git 仓库,创建 feature/vue3-migration 分支
  2. Node.js 版本:确保 Node.js 版本 ≥ 18.0.0(Vite 5.x 要求)
  3. 依赖兼容性检查:使用 npm outdated 检查第三方依赖是否支持 Vue 3

2.2 工具辅助(可选)

使用 Vue 官方迁移工具初步检查代码:

bash

运行

npm install -g @vue/cli-plugin-vue3-migration
vue-cli-service vue3-migration

三、依赖变更清单

3.1 package.json 脚本命令变更

表格

命令 升级前 (Vue CLI) 升级后 (Vite) 说明
启动开发服务器 npm run serve npm run dev Vite 开发服务器,支持 HMR 热更新
生产构建 npm run build npm run build 使用 Rollup 打包,产物更优化
预览构建结果 npm run preview 本地预览生产构建产物
类型检查 npx tsc --noEmit TypeScript 类型检查,不生成文件

3.2 依赖包变更明细

3.2.1 移除的依赖

表格

依赖包 移除原因
vue-template-compiler Vue 3 不再需要单独的模板编译器,已集成到 @vitejs/plugin-vue
@vue/cli-service@vue/cli-plugin-babel@vue/cli-plugin-router 替换为 Vite 构建工具链
element-ui Vue 2 专属 UI 库,替换为 Element Plus
vuex Vue 3 官方推荐使用 Pinia,更轻量且 TypeScript 支持更好
3.2.2 新增的依赖

json

{
  "dependencies": {
    "vue": "^3.4.0",
    "vue-router": "^4.2.0",
    "pinia": "^2.1.7",
    "element-plus": "^2.4.4",
    "@element-plus/icons-vue": "^2.3.1"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.0",
    "vite": "^5.0.0",
    "typescript": "^5.3.3",
    "vue-tsc": "^1.8.27"
  }
}

四、核心文件变更详解

4.1 入口文件 main.js

4.1.1 升级前 (Vue 2)

javascript

运行

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import request from '@/utils/request'

Vue.config.productionTip = false
Vue.use(ElementUI, { size: 'mini' })
Vue.prototype.request = request

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
4.1.2 升级后 (Vue 3)

javascript

运行

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import request from '@/utils/request'

const app = createApp(App)
app.use(ElementPlus, { size: 'default' })
app.use(router)
app.use(createPinia())
app.config.globalProperties.$request = request
app.mount('#app')
4.1.3 核心变化详解

表格

变更项 Vue 2 写法 Vue 3 写法 说明
创建应用 new Vue() createApp(App) Vue 3 采用函数式创建,支持多个应用实例
插件注册 Vue.use(Plugin) app.use(Plugin) 插件注册绑定到具体应用实例,而非全局
全局属性 Vue.prototype.$xxx app.config.globalProperties.$xxx 全局属性挂载到应用配置,避免污染全局
挂载方式 new Vue().$mount('#app') app.mount('#app') 更简洁的挂载 API

4.2 路由配置 router/index.js

4.2.1 升级前 (Vue Router 3)

javascript

运行

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'

Vue.use(VueRouter)
const routes = [
  { path: '/', name: 'Home', component: Home },
  { path: '/about', name: 'About', component: () => import('@/views/About.vue') }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

router.beforeEach((to, from, next) => {
  const user = store.state.user
  if (to.meta.requiresAuth && !user) next('/login')
  else next()
})

export default router
4.2.2 升级后 (Vue Router 4)

javascript

运行

import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import { useMainStore } from '@/store'

const routes = [
  { path: '/', name: 'Home', component: Home },
  { path: '/about', name: 'About', component: () => import('@/views/About.vue') }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes,
  scrollBehavior(to, from, savedPosition) {
    return savedPosition || { top: 0 }
  }
})

router.beforeEach((to, from) => {
  const store = useMainStore()
  const user = store.user
  if (to.meta.requiresAuth && !user) return '/login'
})

export default router

export function resetRouter() {
  const newRouter = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes
  })
  router.matcher = newRouter.matcher
}

4.3 状态管理(Vuex → Pinia)

4.3.1 升级前 (Vuex)

javascript

运行

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
  state: { user: null, currentPathName: '' },
  getters: { isLoggedIn: state => !!state.user },
  mutations: {
    SET_USER(state, user) { state.user = user },
    LOGOUT(state) { state.user = null }
  },
  actions: {
    login({ commit }, user) { commit('SET_USER', user) },
    logout({ commit }) { commit('LOGOUT') }
  }
})
4.3.2 升级后 (Pinia)

javascript

运行

import { defineStore } from 'pinia'
import router, { resetRouter } from '@/router'

export const useMainStore = defineStore('main', {
  state: () => ({
    user: JSON.parse(localStorage.getItem('user') || 'null'),
    currentPathName: localStorage.getItem('currentPathName') || ''
  }),
  getters: { isLoggedIn: (state) => !!state.user },
  actions: {
    login(user) { this.user = user },
    logout() {
      this.user = null
      router.push('/login')
      resetRouter()
    }
  }
})

4.4 UI 组件库适配(Element UI → Element Plus)

4.4.1 全局方法调用变更

表格

使用场景 升级前 升级后
消息提示 this.$message.success('') ElMessage.success('')
确认弹窗 this.$confirm('') ElMessageBox.confirm('')
4.4.2 图标使用变更

vue

<script setup>
import { Edit, Search } from '@element-plus/icons-vue'
</script>
<template>
  <el-icon><Edit /></el-icon>
  <el-button :icon="Search">搜索</el-button>
</template>

4.5 样式深度选择器变更

4.5.1 升级前 (Vue 2)

css

::v-deep .el-input__inner { background: #f5f7fa; }
4.5.2 升级后 (Vue 3)

css

:deep(.el-input__inner) { background: #f5f7fa; }
4.5.3 注意事项
  • ::v-deep>>>/deep/ 在 Vue 3 中已废弃,必须使用 :deep()
  • :deep() 必须包裹目标选择器,不能单独使用
  • <style scoped> 下深度选择器仅作用于当前组件子组件

4.6 组件导入规范变更

Vite 强制要求导入组件必须加 .vue 后缀:

javascript

运行

// 升级前
import Aside from '@/components/Aside'
// 升级后
import Aside from '@/components/Aside.vue'

五、Composition API 迁移示例

5.1 升级前 (Options API)

vue

<script>
export default {
  data() { return { form: {}, user: {} } },
  created() { this.getData() },
  methods: {
    async getData() { /* 请求逻辑 */ },
    saveData() { /* 保存逻辑 */ }
  }
}
</script>

5.2 升级后 (Composition API + script setup)

vue

<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'

const emit = defineEmits(['refreshData'])
const user = ref({})
const form = reactive({})

onMounted(() => { getData() })

const getData = async () => { /* 请求逻辑 */ }
const saveData = async () => {
  await request.post('/api/user/save', form)
  ElMessage.success('保存成功')
  emit('refreshData')
}
</script>

六、构建配置变更

6.1 vite.config.ts

typescript

运行

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

export default defineConfig({
  plugins: [vue()],
  resolve: { alias: { '@': path.resolve(__dirname, './src') } },
  server: {
    port: 8080,
    proxy: { '/api': { target: 'http://localhost:9090', changeOrigin: true } }
  },
  build: { chunkSizeWarningLimit: 400 }
})

6.2 index.html 入口文件

html

预览

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>XX业务管理系统</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

七、常见问题与解决方案

表格

错误现象 原因 解决方法
组件导入找不到文件 缺少 .vue 后缀 所有组件导入加 .vue
this.$message 未定义 Vue 3 无全局方法 导入 ElMessage 使用
深度选择器失效 语法废弃 替换为 :deep()
路由报错 removeRoute API 变更 使用 resetRouter

八、升级验证清单

  • npm install 依赖安装成功
  • npm run dev 开发服务正常启动
  • ✅ 登录、路由、组件渲染正常
  • npm run build 生产构建无报错
  • ✅ TypeScript 类型检查通过

九、升级成果

表格

指标 升级前 升级后 改善幅度
开发启动时间 30-60s 5-10s 提升 6-12 倍
热更新速度 1-3s <100ms 提升 10-30 倍
首屏体积 ~352KB ~47KB 减少 87%

十、参考文档


📌 文末说明

本文为企业级 Vue2 升级 Vue3 实战文档,已完成隐私脱敏,适用于所有 Vue2 老项目升级参考。完整文档

#Vue #Vue3 #Vite #前端升级 #ElementPlus #Pinia

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐