1、创建一个vue3的项目

使用命令:vue create projectName,按照提示进行创建。

2、安装依赖

1)将原项目中的package.json下的dependencies节点的内容删掉vue、element-ui、vuex的节点,追加到新项目的package.json中,然后安装element-plus、pinia

npm install element-plus pinia

yarn add element-plus pinia

2)继续安装剩余依赖,执行npm install或yarn install

3、整理代码

1)将原项目src目录的代码拷贝到新项目中,不要直接复制main.js。

2)修改main.js,根据自己代码的具体情况进行修改,此处为示例。

import {
  createApp
} from 'vue'
import ElementPlus from 'element-plus'
import locale from 'element-plus/es/locale/lang/zh-cn';
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
import * as echarts from 'echarts';
import dayjs from 'dayjs';
import isoWeek  from 'dayjs/plugin/isoWeek'
import 'dayjs/locale/zh-cn';
import App from './App.vue'
import router from './router'
import {
  createPinia
} from 'pinia'
import installElementPlus from './plugins/element'
import {
  ElMessageBox
} from 'element-plus'
import axios from 'axios'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
// 引入项目代码中的一些全局提示、方法和变量等
import message from './common/utils/message'
import utils from './common/utils/utils'
import vars from './common/utils/vars'
// 引入项目代码中字体样式
import "./common/css/iconfont/iconfont.css"

const pinia = createPinia()
let app = null

dayjs.extend(isoWeek)
dayjs.locale('zh-cn');

const render = (props = {}) => {
  const {
    container
  } = props
  app = createApp(App)

  app
    .use(ElementPlus, {
      locale
    })
    .use(dayjs)
    .use(pinia)
    .use(router)
    .mount(container ? container.querySelector('#app') : '#app')

  // 全局方法挂载
  app.config.globalProperties.$echarts = echarts;
  app.config.globalProperties.messages = message
  app.config.globalProperties.utils = utils
  app.config.globalProperties.$confirm = ElMessageBox.confirm;
  app.config.globalProperties.vars = vars
  // 注册图标
  for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
  }
  // 注册全局组件开始
  const requireComponent = require.context(
    './common/components',
    false,
    /Base[A-Z]\w+\.(vue|js)$/
  )
  requireComponent.keys().forEach(fileName => {
    const componentConfig = requireComponent(fileName)
    const componentName = upperFirst(
      camelCase(
        fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
      )
    )
    // 全局注册组件
    app.component(
      componentName,
      componentConfig.default || componentConfig
    )
  })
  // 注册全局组件end
}

3)修改vue.config.js,根据自己代码的具体情况进行修改,此处为示例。

const {
    defineConfig
} = require('@vue/cli-service')
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const {
    ElementPlusResolver
} = require('unplugin-vue-components/resolvers')
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
const env = process.env.NODE_ENV
const packageName = require('./package.json').name
module.exports = defineConfig({
    publicPath: '/',
    outputDir: 'dist',
    transpileDependencies: true,
    productionSourceMap: false,
    css: {
        loaderOptions: {
            // 配置全局sass/scss
            // 给 sass-loader 传递选项
            sass: {
                // @/ 是 src/ 的别名
                additionalData: `@import "@/common/css/init.scss";`
            }
        }
    },
    chainWebpack: (config) => {
        config.module
            .rule('vue')
            .use('vue-loader')
            .tap((options) => {
                return {
                    ...options,
                    reactivityTransform: true
                }
            })
    },
    configureWebpack: {
        plugins: [
            AutoImport({ // 按需加载
                resolvers: [ElementPlusResolver()]
            }),
            Components({
                resolvers: [ElementPlusResolver()]
            }),
            new NodePolyfillPlugin()
        ],
        output: {
            library: `${packageName}-[name]`,
            libraryTarget: 'umd'
        }
    },
    lintOnSave: false,
    pages: {
        index: {
            entry: 'src/main.js',
            title: 'title'
        }
    },
    devServer: {
        client: {
            overlay: false
        },
        open: true,
        host: 'localhost',
        port: 9004,
        headers: {
            'Access-Control-Allow-Origin': '*'
        },
        proxy: {
            '/api': {
                target: 'http://127.0.0.1:8080',
                ws: true,
                changeOrigin: true,
                pathRewrite: {
                    '^/api': '/'
                }
            }
    }
})

4、运行项目

项目运行起来后,应该有一些报错,然后就逐个解决报错,这里列举一些,我在项目中遇到的,提供参考。因为vue3中也支持vue2的选项式的写法,所以大部分代码不需要做调整,只是element的组件部分需要根据最新的组件用法使用,需要调整的也不多。

4.1、修改状态管理store

原项目中的状态管理的部分store需要修改,使用vue3匹配的pinia进行状态管理,以下是用户相关的状态信息的示例代码。

import {
    defineStore
} from 'pinia'

const userStore = defineStore(
    'user', {
        state: () => ({
            userInfos: {},
            currentUser: null, // 当前用户
            currentUserDetails: null, // 当前用户详细信息
        }),
        actions: {
            // 设置当前用户详细信息
            setCurrentUserDetails(value) {
                this.currentUserDetails = value;
            }
        }
    })

export default userStore

代码中使用了this.$store的修改方法如下:

//引入
import { userStore } from "@/store"

data数据中加入state
state: userStore()

把this.$store.state.修改为this.state.

4.2、修改路由相关

import {
  createRouter,
  createWebHistory
} from 'vue-router'
const Header = () => import('@/views/header/Header.vue')
const routes = [{
        path: '/',
        name: 'Home',
        meta: {
            title: '首页',
            requiresAuth: true,
            header: "home"
        },
        redirect: '/home',
        components: {
            default: Home,
            header: Header
        }
    }
]

import globalStore from '@/store/global'
import userServer from '@/api/user.server'
let gloStore = {}
const router = createRouter({
  history: createWebHistory(),
  routes
})
router.beforeEach((to, from, next) => {
  
})

export default router

4.3、路由信息报错的情况

1)使用useRoute来获取当前路由的信息,然后通过path属性获取完整的路径

import { useRoute } from 'vue-router'
export default {
    setup() {
    const route = useRoute()
    // 获取完整路径
    const fullPath = route.path
    console.log(fullPath)
    // 其他逻辑...
    return {
      // 返回需要暴露给模板的数据
      fullPath
    }
   }
}

2)监听路由

watch(() => route.path, (newPath, oldPath) => {
    let current = router.currentRoute
    let path = current.value
    console.log('path', path)
})

4.4、其他报错

1、组件中v-on="$listeners"移除,只需要保留v-bind="$attrs"

2、el-button组件,type="text"需要修改为 link,例如:

<el-button type="primary" link >按钮</el-button>

3、分页组件中的current-page.sync,修改为 v-model:current-page。

4、vue3没有全局过滤器,使用计算属性或者全局方法替代。

5、table组件,列的template中slot-scope删掉,换成#default。

6、通过ref获取子组件中的数据或方法,就在子组件中通过defineExpose将需要用到的数据或方法暴露出去,然后在父组件中使用ref去调用时就不会报错了。

5、参考文档

Vue 3 迁移指南 | Vue 3 迁移指南

入门 | Vue Router

定义一个 Store | Pinia 中文文档

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐