安装项目
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
- 下载依赖包
yarn add element-plus
- 完整引入
在项目入口文件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')
- 按需导入
- 首先安装依赖包
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()],
}),
],
静态路由搭建
- 安装依赖
yarn add vue-router
- 路由表搭建
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
- 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)
- 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
- 添加路由守卫
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')
}
}
}
})
动态路由搭建
- 定义路由的接口
export interface IUserMenu{
_id:string,
title:string,
pid:string,
path:string,
icon:string,
children:Array<IUserMenu>
}
export interface StateType{
permissionList:Array<IUserMenu>
}
路由是数组所以定义为Array
- 安装pinia
yarn add pinia
- 创建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主要是用于异步操作和业务逻辑的处理
- 安装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
- 在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)
}
- 在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循环遍历得到每个匹配到的路径,再通过动态导入对应的组件进行处理。
- 在路由守卫中调用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
创建菜单组件
- 创建路由限制接口 IUserMenu
export interface IUserMenu{
_id:string,
title:string,
pid:string,
path:string,
icon:string,
children:Array<IUserMenu>
}
- 导入Mounted生命周期和ref
import { onMounted,red} from 'vue'
- 导入Api
import $api from 'api地址'
- 声明Menus数据变量
const Menus = ref<Array<IUserMenu>>([])
- 创建动态获取用户菜单
const getMenus = async () => {
const result = await $api.user.getMenus()
Menus.value = result.data.data
dynamicRoute()
}
- 挂载方法
onMounted(() => {
getMenus()
})
- 菜单的模板
- 如果要让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的缩写文章来源:https://www.toymoban.com/news/detail-448954.html
main.js中进行路由的配置
- 导入createApp和App组件
import { createApp } from 'vue'
import App from '@/App.vue'
- 导入路由
import router from '@/router/index'
- 导入Element相关配置
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
- 导入element中的icon
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
- 导入动态获取路由的方法
import dynamicRoute from '@/utils/dynicRoute'
- 导入仓库入库文件
import pinia from '@/store'
- 使用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)之后文章来源地址https://www.toymoban.com/news/detail-448954.html
到了这里,关于Vue3添加动态路由及项目搭建的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!