vue實(shí)現(xiàn)前端控制動(dòng)態(tài)路由的示例代碼
在 Vue.js 中,動(dòng)態(tài)路由是一種根據(jù)不同用戶權(quán)限或其他因素動(dòng)態(tài)改變路由列表的功能。這種機(jī)制允許開發(fā)者根據(jù)后端提供的權(quán)限數(shù)據(jù)動(dòng)態(tài)渲染前端路由,實(shí)現(xiàn)多用戶權(quán)限系統(tǒng),不同用戶展示不同的導(dǎo)航菜單。
動(dòng)態(tài)路由的配置
動(dòng)態(tài)路由的配置涉及到前端路由的動(dòng)態(tài)加載和解析。通常,動(dòng)態(tài)路由的數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫中,前端通過接口獲取當(dāng)前用戶對(duì)應(yīng)的路由列表并進(jìn)行渲染。以下是實(shí)現(xiàn)動(dòng)態(tài)路由的基本步驟:
靜態(tài)路由配置:首先,需要配置靜態(tài)路由,如登錄頁、首頁等。這些路由通常不會(huì)改變,可以直接寫在路由配置文件中。
// 創(chuàng)建路由實(shí)例
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: allRoutes
})// 所有路由定義(靜態(tài)+動(dòng)態(tài))
const allRoutes = [
// 基礎(chǔ)路由
{
path: '/',
name: 'login',
component: () => import("@/views/LoginView.vue")
},
{
path: '/404',
name: '404',
component: () => import('@/views/Error/404View.vue')
},
// 動(dòng)態(tài)路由容器(登錄后內(nèi)容)
{
path: '/layout',
name: 'layout',
component: () => import('@/Layout/MainLayout.vue'),
children: [] // 初始為空,動(dòng)態(tài)注入路由
},
]動(dòng)態(tài)路由獲取:在用戶登錄后,前端調(diào)用后端接口獲取用戶對(duì)應(yīng)的權(quán)限類型role。
// 需要權(quán)限控制的路由配置(扁平化結(jié)構(gòu)更易管理)
const dynamicRouteConfigs = [
{
path: '/home', // 注意使用相對(duì)路徑
name: 'home',
component: () => import('@/views/HomeView.vue'),
meta: {
title: '首頁',
icon: 'House',
roles: ['*'] // *表示所有登錄用戶
}
},
{
path: 'user/list',
name: 'UserList',
component: () => import('@/views/user/ListView.vue'),
meta: {
title: '用戶列表',
roles: ['1','2']
}
},
{
path: 'user/role',
name: 'UserRole',
component: () => import('@/views/user/RoleView.vue'),
meta: {
title: '角色管理',
roles: ['1']
}
}
]路由過濾的函數(shù)
// 權(quán)限過濾方法修正
const filterRoutes = (routes, roles) => {
// 遞歸處理每個(gè)路由節(jié)點(diǎn)
return routes.filter(route => {
// 獲取當(dāng)前路由需要的權(quán)限角色
const requiredRoles = route.meta?.roles || []
// 檢查當(dāng)前路由是否滿足權(quán)限要求
const hasPermission = requiredRoles.includes('*') || requiredRoles.includes(roles + '')
// 遞歸處理子路由(關(guān)鍵修改點(diǎn))
if (route.children) {
const filteredChildren = filterRoutes(route.children, roles)
// 保留有效子路由:只有當(dāng)子路由存在時(shí)才保留children
route.children = filteredChildren.length ? filteredChildren : undefined
}
/*
路由保留條件(核心邏輯):
1. 當(dāng)前路由自身有權(quán)限 或
2. 存在有效的子路由(即使當(dāng)前路由沒有權(quán)限,但子路由有權(quán)限時(shí)保留父級(jí)容器)
*/
return hasPermission || (route.children && route.children.length > 0)
})
}動(dòng)態(tài)添加路由,先清空已有的動(dòng)態(tài)路由,然后再調(diào)用添加路由的函數(shù)進(jìn)行添加,
// 動(dòng)態(tài)添加路由到layout
const addDynamicRoutes = (roles) => {
// 清空已有動(dòng)態(tài)路由
const layout = router.getRoutes().find(r => r.name === 'layout')
layout.children.forEach(child => {
router.removeRoute(child.name)
})
// 過濾并添加新路由
const allowedRoutes = filterRoutes(dynamicRouteConfigs, loginStore().roles);
allowedRoutes.forEach(route => { router.addRoute('layout', route); });
console.log(allowedRoutes);
sessionStorage.setItem('menuPath',JSON.stringify(allowedRoutes));//存儲(chǔ)的篩選過的動(dòng)態(tài)路由
sessionStorage.setItem('menuName',JSON.stringify(router.getRoutes()));//存儲(chǔ)的所有動(dòng)態(tài)路由
console.log(router.getRoutes());
// 確保404最后處理
router.addRoute({
path: '/:pathMatch(.*)*',
redirect: '/404'
})
}導(dǎo)航守衛(wèi)部分,路由跳轉(zhuǎn)前的操作。
獲取用戶狀態(tài)存儲(chǔ)實(shí)例,檢測(cè)登錄狀態(tài);判斷用戶未登錄時(shí)直接跳轉(zhuǎn)到登錄頁進(jìn)行登錄;已登錄訪問登錄頁處理,防止已登錄用戶重復(fù)訪問登錄頁;動(dòng)態(tài)路由注入。
使用router.addRoute()注入路由;路由跳轉(zhuǎn)處理,清除舊路由(避免重復(fù));
// 路由守衛(wèi)修改部分(router/index.ts)
router.beforeEach(async (to, from, next) => {
const store = loginStore()
const isLogin = !!store.id
// 未登錄狀態(tài)處理
if (!isLogin) {
return to.path === '/' ? next() : next('/')
}
// 已登錄但訪問登錄頁時(shí)重定向
if (to.path === '/') {
return next('/home')
}
// 動(dòng)態(tài)路由加載邏輯
if (!store.routesLoaded) {
try {
// 直接從store獲取已保存的角色信息
const userRoles = store.roles
console.log(userRoles);
// 如果角色信息不存在則拋出錯(cuò)誤
if (!userRoles || userRoles.length === 0) {
throw new Error('用戶角色信息未獲取')
}
// 添加動(dòng)態(tài)路由
addDynamicRoutes(userRoles)
// 在添加路由后打印
console.log('當(dāng)前所有路由:', router.getRoutes().map(r => r.path))
// 更新加載狀態(tài)
store.setRoutesLoaded(true)
// 使用replace方式跳轉(zhuǎn)避免重復(fù)記錄歷史
return next({ ...to, replace: true })
} catch (error) {
console.error('路由加載失敗:', error)
// 清除用戶狀態(tài)并跳轉(zhuǎn)登錄頁
store.$reset()
return next('/')
}
}
next()
})最后,總結(jié)整個(gè)流程,強(qiáng)調(diào)關(guān)鍵點(diǎn),幫助用戶全面理解路由守衛(wèi)的工作機(jī)制和實(shí)現(xiàn)動(dòng)態(tài)路由加載的正確方法。
到此這篇關(guān)于vue實(shí)現(xiàn)前端控制動(dòng)態(tài)路由的示例代碼的文章就介紹到這了,更多相關(guān)vue 動(dòng)態(tài)路由內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
說說Vue.js中的functional函數(shù)化組件的使用
這篇文章主要介紹了說說Vue.js中的functional函數(shù)化組件的使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-02-02
vue+echarts實(shí)現(xiàn)可拖動(dòng)節(jié)點(diǎn)的折線圖(支持拖動(dòng)方向和上下限的設(shè)置)
制作一個(gè)折線圖用于顯示當(dāng)前24小時(shí)的數(shù)據(jù),并且可以通過拖動(dòng)折現(xiàn)圖設(shè)置數(shù)據(jù),接下來通過本文給大家分享vue+echarts實(shí)現(xiàn)可拖動(dòng)節(jié)點(diǎn)的折線圖(支持拖動(dòng)方向和上下限的設(shè)置),感興趣的朋友跟隨一起學(xué)習(xí)吧2019-04-04
Vue.js學(xué)習(xí)筆記之 helloworld
vue是法語中視圖的意思,Vue.js是一個(gè)輕巧、高性能、可組件化的MVVM庫,同時(shí)擁有非常容易上手的API。有需要的小伙伴可以參考下2016-08-08
Vue聯(lián)動(dòng)Echarts實(shí)現(xiàn)數(shù)據(jù)大屏展示
這篇文章主要為大家介紹了Vue聯(lián)動(dòng)Echarts實(shí)現(xiàn)數(shù)據(jù)大屏的展示示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
vue實(shí)現(xiàn)移動(dòng)端圖片裁剪上傳功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)移動(dòng)端圖片裁剪上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
前端框架Vue父子組件數(shù)據(jù)雙向綁定的實(shí)現(xiàn)
Vue項(xiàng)目中經(jīng)常使用到組件之間的數(shù)值傳遞,實(shí)現(xiàn)的方法很多,但是原理上基本大同小異。這篇文章將給大家介紹Vue 父子組件數(shù)據(jù)單向綁定與Vue 父子組件數(shù)據(jù)雙向綁定的對(duì)比從而認(rèn)識(shí)雙向綁定2021-09-09

