安裝項(xiàng)目
yarn create vite vue3-project
安裝依賴包
yarn add @types/node -D
在tsconfig.json中配置別名
"baseUrl": "./",
"paths": {
"@/*":["src/*"]
},
在vite中進(jìn)行配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
導(dǎo)入resolve
import {resolve} from 'path'
配置resolve
export default defineConfig({
plugins: [vue()],
resolve:{
alias:{
"@":resolve(__dirname,'./src')
}
},
})
安裝elementUi-Plus
- 下載依賴包
yarn add element-plus
- 完整引入
在項(xiàng)目入口文件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')
- 按需導(dǎo)入
- 首先安裝依賴包
npm install -D unplugin-vue-components unplugin-auto-import
- 在項(xiàng)目入口文件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()],
}),
],
靜態(tài)路由搭建
- 安裝依賴
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
響應(yīng)的類型限制為:AxiosResponse
- 添加路由守衛(wèi)
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')
}
}
}
})
動(dòng)態(tài)路由搭建
- 定義路由的接口
export interface IUserMenu{
_id:string,
title:string,
pid:string,
path:string,
icon:string,
children:Array<IUserMenu>
}
export interface StateType{
permissionList:Array<IUserMenu>
}
路由是數(shù)組所以定義為Array
- 安裝pinia
yarn add pinia
- 創(chuàng)建store的模塊
1. 導(dǎo)入defineStore
import {defineStore} from 'pinia'
2. 導(dǎo)入路由限定接口
import { stateType} from 'type地址'
3. 導(dǎo)入api
import $api from 'api地址'
4. 導(dǎo)入路由類型限制
import {RouteRecordRaw} from 'vue-router'
- RouteRecordRaw是Vue Router v4.x中新增的一種路由配置類型,可以使得我們在編寫路由時(shí)更加方便靈活。它定義在@vue/router中,并且支持使用TypeScript類型推斷
5. 導(dǎo)入動(dòng)態(tài)獲取一組文件符合特定模式的模塊getViews方法
import {getViews} from '@/utils/getViews.ts'
6. 創(chuàng)建倉庫
const store = defineStore('auth',{
state:():stateType=>{
return {
permissionList:[]
}
}
})
7. 根據(jù)action異步獲取菜單路由
actions:{
async getAuthMenuAsync(){
const result = await $api.user.getMenus()
this.permissionList = result.data.data
}
}
8. 通過getters獲取動(dòng)態(tài)路由
getters:{
getHomeRoute(state:StateType){
let homeRouteObj:RouteRecordRaw = {
path:'/home',
component:()=>import('../../views/HomePage.vue'),
children:[]
}
// 定義一個(gè)數(shù)組用來存放子菜單的路由
let arr:Array<RouteRecordRaw>=[]
// 添加判斷解決首次進(jìn)入token失效,路由沒有跳轉(zhuǎn)的問題
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)
})
}
})
}
// 將定義的數(shù)組賦值給路由對象中的子路由
homRouteObj.children = arr
return homRouteObj
}
}
因?yàn)間etters可以直接獲取狀態(tài),action主要是用于異步操作和業(yè)務(wù)邏輯的處理
- 安裝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
}
]
}
})
這時(shí)會(huì)報(bào)錯(cuò),需要在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文件中創(chuàng)建動(dòng)態(tài)路由添加的方法
1. 導(dǎo)入useAuthStore倉庫
import useAuthStore from '@/store/modules/user'
2. 導(dǎo)入路由
import router from '@/router/index'
3. 編寫方法
const dynamicRoute = ()=>{
const store = useAuthStore()
- 將異步獲取菜單權(quán)限的方法結(jié)構(gòu)出來
const {getAuthMenuAsync} = store
- 調(diào)用異步方法
getAuthMenuAsync()
- 調(diào)用獲取路由的方法
const homeRoute= store.getDynicRoute
- 將獲取的路由添加到路由
router.addRoute(homeRoute)
}
- 在utils文件中創(chuàng)建動(dòng)態(tài)獲取Component的方法
export const getViews(path:string){
let modules = import.meta.glob('../**/*.vue')
return modules[path]
}
import.meta.glob是ES2020的一個(gè)新特性,用于動(dòng)態(tài)獲取一組文件符合特定模式的模塊,返回一個(gè)鍵/值對象形式的Promise??梢允褂胕mport.meta.glob將所有以.vue結(jié)尾的文件導(dǎo)入為模塊,并且可以使用for…in循環(huán)遍歷得到每個(gè)匹配到的路徑,再通過動(dòng)態(tài)導(dǎo)入對應(yīng)的組件進(jìn)行處理。
- 在路由守衛(wèi)中調(diào)用utils中動(dòng)態(tài)獲取路由的方法
1. 導(dǎo)入動(dòng)態(tài)獲取路由的方法
import dynamicRoute from '@/utils/dynicRoute'
2. 導(dǎo)入路由的限制類型
import {RouteRecordRaw,createRouter,createWebHistory} from 'vue-router'
3. 導(dǎo)入api
import $api from '@/api/index'
4. 導(dǎo)入elmessage
import { ElMessage } from 'element-plus'
5. 導(dǎo)入動(dòng)態(tài)路由
import dynamicRoute from '@/utils/dynicRoute'
6. 創(chuàng)建路由表
const routes: Array<RouteRecordRaw> = [
{
path: '/login',
component: () => import('@/views/Login.vue')
},
- 設(shè)置路由重定向
{
path: '/',
redirect: '/home'
}
]
7. 創(chuàng)建路由
const router = createRouter({
history: createWebHistory(),
routes
})
8. 添加路由守衛(wèi)
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()
- 調(diào)用動(dòng)態(tài)獲取路由的方法
dynamicRoute()
next()
} catch (error) {
ElMessage.warning('token已失效,請重新登錄')
next('/login')
}
}
}
})
9. 導(dǎo)出路由
export default router
創(chuàng)建菜單組件
- 創(chuàng)建路由限制接口 IUserMenu
export interface IUserMenu{
_id:string,
title:string,
pid:string,
path:string,
icon:string,
children:Array<IUserMenu>
}
- 導(dǎo)入Mounted生命周期和ref
import { onMounted,red} from 'vue'
- 導(dǎo)入Api
import $api from 'api地址'
- 聲明Menus數(shù)據(jù)變量
const Menus = ref<Array<IUserMenu>>([])
- 創(chuàng)建動(dòng)態(tài)獲取用戶菜單
const getMenus = async () => {
const result = await $api.user.getMenus()
Menus.value = result.data.data
dynamicRoute()
}
- 掛載方法
onMounted(() => {
getMenus()
})
- 菜單的模板
- 如果要讓elementplus的menu菜單啟用vu-router路由模式,需要在el-menu標(biāo)簽中設(shè)置:router=“true”
- 在Home的el-main區(qū)域內(nèi)容配置二級路由出口
<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圖標(biāo)使用動(dòng)態(tài)組件component, #title是v-slot的縮寫文章來源:http://www.zghlxwxcb.cn/news/detail-448954.html
main.js中進(jìn)行路由的配置
- 導(dǎo)入createApp和App組件
import { createApp } from 'vue'
import App from '@/App.vue'
- 導(dǎo)入路由
import router from '@/router/index'
- 導(dǎo)入Element相關(guān)配置
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
- 導(dǎo)入element中的icon
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
- 導(dǎo)入動(dòng)態(tài)獲取路由的方法
import dynamicRoute from '@/utils/dynicRoute'
- 導(dǎo)入倉庫入庫文件
import pinia from '@/store'
- 使用pinia,ElementPlus,router并且掛載app
const app = createApp(App)
// 循環(huán)遍歷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')
一定要注意動(dòng)態(tài)路由的添加必須放在app.use(router)之前,app.use(pinia)之后文章來源地址http://www.zghlxwxcb.cn/news/detail-448954.html
到了這里,關(guān)于Vue3添加動(dòng)態(tài)路由及項(xiàng)目搭建的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!