Vue3添加动态路由及项目搭建

本文详细介绍了如何使用Vite搭建Vue3项目,包括安装依赖、配置别名、引入ElementPlus以及按需导入。同时,文章讲解了VueRouter的静态和动态路由搭建,axios的二次封装,以及使用Pinia进行状态管理并实现路由守卫和动态获取路由。最后,提到了如何处理菜单组件并展示动态路由。
摘要由CSDN通过智能技术生成

安装项目

yarn create vite vue3-project

安装依赖包

yarn add @types/node -D

在tsconfig.json中配置别名

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

在vite中进行配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
导入resolve
import {resolve} from 'path'
配置resolve
export default defineConfig({
  plugins: [vue()],
  resolve:{
    alias:{
      "@":resolve(__dirname,'./src')
    }
  },
})

安装elementUi-Plus

  1. 下载依赖包
 yarn add element-plus
  1. 完整引入
    在项目入口文件main.js
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')
  1. 按需导入
    • 首先安装依赖包
npm install -D unplugin-vue-components unplugin-auto-import
  • 在项目入口文件main.js
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  // ...
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],

静态路由搭建

  1. 安装依赖
yarn add vue-router
  1. 路由表搭建
import {RouteRecordRaw,createRouter, createWebHashHistory} from 'vue-router';
const routes:Array<RouteRecordRaw> = [
    {
        path:'/login',
        component:()=>import('@/views/Login.vue')
    },
    {
        path:'/',
        redirect:'/homg'
    },
    {
        path:'/home',
        component:()=>import('@/views/HomePage.vue')
    }
]
const router = createRouter({
    routes,
    history:createWebHashHistory()
})
export default router
  1. main.js中配置
import { createApp } from 'vue'
import App from '@/App.vue'
import 'element-plus/dist/index.css'
import router from '@/router/index'
const app = createApp(App)
app.mount('#app')
app.use(router)

  1. axios二次封装
import axios,{AxiosError, AxiosResponse, InternalAxiosRequestConfig} from 'axios';
const newAxios = axios.create({
    baseURL:'http://www.zhaijizhe.cn:3005',
    timeout:5000
})
newAxios.interceptors.request.use((config:InternalAxiosRequestConfig)=>{
    const token = localStorage.getItem('token')
    if(token){
        config.headers.Authorization = token
    }
    return config
})
newAxios.interceptors.response.use((response:AxiosResponse)=>{
    return response
},(error:AxiosError)=>{
    return Promise.reject(error)
})
export default newAxios

请求的类型限制为:InternalAxiosRequestConfig
响应的类型限制为:AxiosResponse

  1. 添加路由守卫
router.beforeEach(async(to,from,next)=>{
    if(to.path == '/login'){
        next()
    }else{
        const token = localStorage.getItem('token')
        if(!token){
            ElMessage.warning('用户未登录,请登录')
            next('/login')
        }else{
            try {
                await $api.user.getMenus()
                 dynamicRoute()
                next()
            } catch (error) {
                ElMessage.warning('token已失效,请重新登录')
                next('/login')
            }
        }
    }
})

动态路由搭建

  1. 定义路由的接口
export interface IUserMenu{
    _id:string,
    title:string,
    pid:string,
    path:string,
    icon:string,
    children:Array<IUserMenu>
}
export interface StateType{
    permissionList:Array<IUserMenu>
}

路由是数组所以定义为Array

  1. 安装pinia
yarn add pinia
  1. 创建store的模块
1. 导入defineStore
import {defineStore} from 'pinia'
2. 导入路由限定接口
import { stateType} from 'type地址'
3. 导入api
import $api from 'api地址'
4. 导入路由类型限制
import {RouteRecordRaw} from 'vue-router'
  - RouteRecordRaw是Vue Router v4.x中新增的一种路由配置类型,可以使得我们在编写路由时更加方便灵活。它定义在@vue/router中,并且支持使用TypeScript类型推断
5. 导入动态获取一组文件符合特定模式的模块getViews方法
import {getViews} from '@/utils/getViews.ts'
6. 创建仓库
const store = defineStore('auth',{
      state:():stateType=>{
        return {
          permissionList:[]
        }
      }
})
7. 根据action异步获取菜单路由
actions:{
  async getAuthMenuAsync(){
    const result = await $api.user.getMenus()
    this.permissionList = result.data.data
  }
}
8. 通过getters获取动态路由
getters:{
  getHomeRoute(state:StateType){
    let homeRouteObj:RouteRecordRaw = {
      path:'/home',
       component:()=>import('../../views/HomePage.vue'),
      children:[]
    }
    // 定义一个数组用来存放子菜单的路由
    let arr:Array<RouteRecordRaw>=[]
   //  添加判断解决首次进入token失效,路由没有跳转的问题
    if(state&&state.permissionList){
            state.permissionList.forEach(item=>{
                if(item.children){
                    item.children.forEach(subItem=>{
                        let routeItem ={
                            path:subItem.path,
                            component:getViews((`../views${subItem.path}.vue`))
                        }
                        ary.push(routeItem)
                    })
                }
            })
           }
    // 将定义的数组赋值给路由对象中的子路由
    homRouteObj.children = arr
    return homRouteObj
  }
}

因为getters可以直接获取状态,action主要是用于异步操作和业务逻辑的处理

  1. 安装pinia持久化插件
yarn add pinia-plugin-persist
  • 在store的user模块中配置persist
const useAuthStore = defineStore('auth', {
    state: (): StateType => { },
    getters:{},
    actions:{},
    persist:{
        enabled:true,
        strategies:[
            {
                key:'userAuth',
                storage:localStorage
            }
        ]
    }
})

这时会报错,需要在tsconfig.json中将 “moduleResolution”: “node”,改为node

  • 在仓库的入口文件中配置插件
import {createPinia} from 'pinia';
import piniaPluginPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPluginPersist)
export default pinia
  1. 在utils文件中创建动态路由添加的方法
1. 导入useAuthStore仓库
import useAuthStore from '@/store/modules/user'
2. 导入路由
import router from '@/router/index'
3. 编写方法
 const dynamicRoute = ()=>{
    const store = useAuthStore()
    - 将异步获取菜单权限的方法结构出来
    const {getAuthMenuAsync} = store
    - 调用异步方法
    getAuthMenuAsync()
    - 调用获取路由的方法
    const homeRoute= store.getDynicRoute
    - 将获取的路由添加到路由
    router.addRoute(homeRoute)
}
  1. 在utils文件中创建动态获取Component的方法
export const getViews(path:string){
   let modules = import.meta.glob('../**/*.vue')
   return modules[path]
}

import.meta.glob是ES2020的一个新特性,用于动态获取一组文件符合特定模式的模块,返回一个键/值对象形式的Promise。可以使用import.meta.glob将所有以.vue结尾的文件导入为模块,并且可以使用for…in循环遍历得到每个匹配到的路径,再通过动态导入对应的组件进行处理。

  1. 在路由守卫中调用utils中动态获取路由的方法
1. 导入动态获取路由的方法
import dynamicRoute from '@/utils/dynicRoute'
2. 导入路由的限制类型
import {RouteRecordRaw,createRouter,createWebHistory} from 'vue-router'
3. 导入api
import $api from '@/api/index'
4. 导入elmessage
import { ElMessage } from 'element-plus'
5. 导入动态路由
import dynamicRoute from '@/utils/dynicRoute'
6. 创建路由表
const routes: Array<RouteRecordRaw> = [
    {
        path: '/login',
        component: () => import('@/views/Login.vue')
    },
    - 设置路由重定向
    {
        path: '/',
        redirect: '/home'
    }
]
7. 创建路由
const router = createRouter({
    history: createWebHistory(),
    routes
})
8. 添加路由守卫
router.beforeEach(async (to, _, next) => {
    if (to.path == '/login') {
        next()
    } else {
        const token = localStorage.getItem('token')
        if (!token) {
            ElMessage.warning('用户未登录,请登录')
            next('/login')
        } else {
            try {
                await $api.user.getMenus()
                - 调用动态获取路由的方法
                dynamicRoute()
                next()
            } catch (error) {
                ElMessage.warning('token已失效,请重新登录')
                next('/login')
            }
        }
    }
})
9. 导出路由
export default router

创建菜单组件

  1. 创建路由限制接口 IUserMenu
export interface IUserMenu{
    _id:string,
    title:string,
    pid:string,
    path:string,
    icon:string,
    children:Array<IUserMenu>
}
  1. 导入Mounted生命周期和ref
import { onMounted,red} from 'vue'
  1. 导入Api
import $api from 'api地址'
  1. 声明Menus数据变量
const Menus = ref<Array<IUserMenu>>([])
  1. 创建动态获取用户菜单
const getMenus = async () => {
    const result = await $api.user.getMenus()
    Menus.value = result.data.data
    dynamicRoute()
}
  1. 挂载方法
onMounted(() => {
    getMenus()
})
  1. 菜单的模板
  • 如果要让elementplus的menu菜单启用vu-router路由模式,需要在el-menu标签中设置:router=“true”
- 在Home的el-main区域内容配置二级路由出口
<template>
    <div>
        <el-menu :router="true" class="elMenu" background-color="#545c64">
            <el-sub-menu v-for="item in Menus" :key="item._id" :index="item._id">
                <template #title>
                    <el-icon>
                        <component :is="item.icon"></component>
                    </el-icon>
                    <span>{{ item.title }}</span>
                </template>
                <el-menu-item v-for="subItem in item.children" :key="subItem._id" :index="subItem.path">
                    <template #title>
                        <span>{{ subItem.title }}</span>
                    </template>
                </el-menu-item>
            </el-sub-menu>
        </el-menu>
    </div>
</template>

其中渲染icons图标使用动态组件component, #title是v-slot的缩写

main.js中进行路由的配置

  1. 导入createApp和App组件
import { createApp } from 'vue'
import App from '@/App.vue'
  1. 导入路由
import router from '@/router/index'
  1. 导入Element相关配置
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
- 导入element中的icon
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
  1. 导入动态获取路由的方法
import dynamicRoute from '@/utils/dynicRoute'
  1. 导入仓库入库文件
import pinia from '@/store'
  1. 使用pinia,ElementPlus,router并且挂载app
const app = createApp(App)
// 循环遍历elementUI的icon
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}
app.use(pinia)
app.use(ElementPlus)
dynamicRoute()
app.use(router)
app.mount('#app')

一定要注意动态路由的添加必须放在app.use(router)之前,app.use(pinia)之后

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值