目錄
前言
一、項(xiàng)目介紹
1.開發(fā)環(huán)境
2.功能
3.項(xiàng)目運(yùn)行截圖??
二、實(shí)現(xiàn)
1.動(dòng)態(tài)路由如何實(shí)現(xiàn)
2.項(xiàng)目目錄介紹
3.核心代碼
4.坑和知識(shí)點(diǎn)
小結(jié)
前言
最近在學(xué)權(quán)限相關(guān)的管理項(xiàng)目,前端用到了動(dòng)態(tài)路由,就是根據(jù)用戶角色顯示不同的菜單,動(dòng)態(tài)添加路由。說著好像很簡(jiǎn)單,但看了很多教程,也跟著教程寫了很多代碼,但最后都跑不通(很多原因,比如:版本問題,教程沒有全部代碼,只有核心代碼片段等)。??????所以,我只能狠下心,寫下這篇博客,方便自己總結(jié),也為了避免大家踩坑。
一、項(xiàng)目介紹
廢話不多說,直接附上項(xiàng)目下載地址:
gitee:https://gitee.com/wusupweilgy/springboot-vue.git
藍(lán)奏云:https://wwp.lanzoup.com/iO74W0r6bcob
1.開發(fā)環(huán)境
前端:vue2+element-ui組件
2.功能
根據(jù)用戶的賬號(hào)密碼,生成不同的菜單,動(dòng)態(tài)添加路由
3.項(xiàng)目運(yùn)行截圖??
?
二、實(shí)現(xiàn)
1.動(dòng)態(tài)路由如何實(shí)現(xiàn)
流程:
- 登錄的時(shí)候,根據(jù)登錄用戶返回此角色可以訪問的頁面的路由和token
- 前端將路由存儲(chǔ)到sessionStorage和vuex中(因?yàn)関uex存儲(chǔ)的數(shù)據(jù)一刷就沒了,所以需要配合sessionStorage)
- 在路由前置守衛(wèi)處動(dòng)態(tài)添加拿到的路由,對(duì)頁面進(jìn)行渲染。
2.項(xiàng)目目錄介紹
- ?assets:存放圖片和樣式
- router:路由配置
- dynamicRoutes.js:動(dòng)態(tài)路由模板
- index.js:靜態(tài)路由
- permission.js:路由前置守衛(wèi)
- store:vuex存儲(chǔ)全局的狀態(tài)變量
- util:工具類
- index.js:動(dòng)態(tài)添加路由工具類
- request.js:axios請(qǐng)求工具類
- views:存放頁面
3.核心代碼
1)/views/Login.vue:登錄(onSubmit方法)成功時(shí),根據(jù)用戶名密碼區(qū)分角色,根據(jù)角色將不同路由和token寫入vuex,dynamicRoutes.js中有兩個(gè)路由模板,分別是user和admin,然后調(diào)用generateRoutes()方法向vue-router中動(dòng)態(tài)添加路由
import {admin,user} from '@/router/dynamicRoutes'
...
onSubmit(formName) {
//為表單綁定驗(yàn)證功能
this.$refs [formName].validate((valid) => {
if (valid) {
if(this.form.username==="user"&&this.form.password==="user"){
store.commit('SET_MENULIST', user);
store.commit('SET_TOKEN', 'user');
}else if(this.form.username==="admin"&&this.form.password==="admin"){
store.commit('SET_MENULIST', admin);
store.commit('SET_TOKEN', 'admin');
}else{
this.$message.error("登錄失敗")
return
}
this.$message.success("登錄成功")
generateRoutes()
this.$router.replace('/')
} else {
this.dialogVisible = true;
return false;
}
});
},
2)/store/index.js:vuex狀態(tài)管理(配合sessionStorage)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token:'',
menuList:[],
isLoadRouters:false
},
getters: {
GET_TOKEN:state => {
state.token = sessionStorage.getItem("token")
return state.token
},
GET_MENULIST:state => {
state.menuList = JSON.parse(sessionStorage.getItem("menuList")||'[]')
return state.menuList
},
GET_ISLOADROUTERS:state=>{
return state.isLoadRouters
}
},
mutations: {
SET_TOKEN:(state,token)=>{
state.token = token
sessionStorage.setItem("token",token);
},
SET_MENULIST:(state,menuList)=>{
state.menuList = menuList
sessionStorage.setItem("menuList",JSON.stringify(menuList));
},
SET_ISLOADROUTERS:(state,isLoadRouters)=>{
state.isLoadRouters = isLoadRouters
}
},
})
3)/util/index.js:方法動(dòng)態(tài)添加路由工具
import router from '../router'
import store from '@/store'
//動(dòng)態(tài)添加路由
export function generateRoutes() {
const _asyncRoutes = store.getters.GET_MENULIST
if(_asyncRoutes==null)
return
_asyncRoutes.forEach(menu => {
if (menu.children) {
menu.children.forEach(m => {
let route = menuToRoute(m, menu.name);
if (route) {
router.addRoute("Home",route)
}
})
}
})
}
//將菜單轉(zhuǎn)換成router可以識(shí)別的路由
const menuToRoute = (menu, parentName) => {
if (!menu.component) {
return null;
} else {
let route = {
name: menu.name,
path: menu.path,
meta: {
parentName: parentName
}
}
route.component = () => import('@/views/' + menu.component + '.vue');
return route;
}
}
4)/router/permission.js:前置路由守衛(wèi),判斷是否登錄和是否已經(jīng)添加過路由
import router from "@/router/index"
import store from "@/store"
import {generateRoutes} from "@/util";
// 檢查是否存在于免登陸白名單
function inWhiteList(toPath) {
const whiteList = ['/login', '/404']
const path = whiteList.find((value) => {
// 使用正則匹配
const reg = new RegExp('^' + value)
return reg.test(toPath)
})
return !!path
}
router.beforeEach((to, from, next) => {
console.group('%c%s', 'color:blue', `${new Date().getTime()} ${to.path} 的全局前置守衛(wèi)----------`)
console.log('所有活躍的路由記錄列表', router.getRoutes())
console.groupEnd()
const token = store.getters.GET_TOKEN
let isLoadRouters = store.state.isLoadRouters
if (inWhiteList(to.path)) {
next()
} else {
//用戶已登錄
if (token && JSON.stringify(store.getters.GET_MENULIST) !== '[]') {
if (isLoadRouters) {
// console.log('路由已添加,直接跳轉(zhuǎn)到目標(biāo)頁面');
next()
} else {
//解決刷新頁面空白
//console.log('重新加載路由,并跳轉(zhuǎn)到目標(biāo)頁');
let menuList = store.getters.GET_MENULIST
store.commit('SET_ISLOADROUTERS', true)
//添加動(dòng)態(tài)路由
generateRoutes(menuList)
next({...to, replace: true})
}
} else {
// console.log('無登錄信息,跳轉(zhuǎn)到登錄頁');
store.commit('SET_ISLOADROUTERS', false)
next(`/login`)
}
}
})
4.坑和知識(shí)點(diǎn)
1)遇到的坑
- 這里有個(gè)大坑,就是頁面刷新的情況,頁面一旦刷新,動(dòng)態(tài)添加的路由也會(huì)清空,只剩靜態(tài)路由,所有還要判斷頁面刷新的操作,這里通過一個(gè)vuex的變量解決,因?yàn)樗⑿虏僮?,vuex的值也會(huì)刷新,所以我在vuex中設(shè)置了isLoadRouters:false這個(gè)變量,如果刷新,這個(gè)值就是默認(rèn)的false
- 第二個(gè)坑就是,在addRoute()之后第一次訪問被添加的路由會(huì)白屏,這是因?yàn)閯倓俛ddRoute()就立刻訪問被添加的路由,然而此時(shí)addRoutes()沒有執(zhí)行結(jié)束,因而找不到剛剛被添加的路由導(dǎo)致白屏。因此需要從新訪問一次路由才行,所以需要next({...to, replace: true}),來保證路由添加完了再進(jìn)入頁面 (可以理解為重進(jìn)一次)。小伙伴可以試試把它換成next(),看會(huì)不會(huì)出現(xiàn)白屏。是
這兩個(gè)坑就已經(jīng)卡了我很長(zhǎng)時(shí)間了,更何況還有其他小坑(哭死我了)
-
用戶點(diǎn)擊退出后,需要重置路由,不然你添加過路由了,再通過addRoute()方法添加路由就會(huì)造成重復(fù)添加路由,瀏覽器的控制臺(tái)會(huì)有警告,不重置也沒事,就是看著有點(diǎn)不舒服。
// 重置路由
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher
}
2)學(xué)到的知識(shí)點(diǎn)
-
js語法:兩個(gè)感嘆號(hào),將非布爾型變量轉(zhuǎn)為布爾值文章來源:http://www.zghlxwxcb.cn/news/detail-737730.html
// 檢查是否存在于免登陸白名單
function inWhiteList(toPath) {
const whiteList = ['/login', '/404']
const path = whiteList.find((value) => {
// 使用正則匹配
const reg = new RegExp('^' + value)
return reg.test(toPath)
})
return !!path
}
- component: () => import("@/views/Index") 實(shí)現(xiàn)路由組件懶加載。vue這種單頁面應(yīng)用單頁面應(yīng)用單頁面應(yīng)用,如果我們不去做路由懶加載,打包之后的文件將會(huì)異常的大,就會(huì)造成進(jìn)入首頁時(shí),需要加載的內(nèi)容過多,時(shí)間過長(zhǎng),會(huì)出現(xiàn)長(zhǎng)時(shí)間的白屏,不利于用戶體驗(yàn),運(yùn)用懶加載就可以將頁面進(jìn)行劃分,需要的時(shí)候加載頁面,可以有效的分擔(dān)首頁所承擔(dān)的加載壓力,減少首頁加載用時(shí)。
- next({...to, replace: true}) 重新訪問一次路由,避免路由還沒添加完成就訪問路
- router.matcher = newRouter.matcher相當(dāng)于重置路由,避免重復(fù)添加路由
小結(jié)
本文介紹了使用Vue實(shí)現(xiàn)動(dòng)態(tài)路由。關(guān)于這個(gè)東西,我網(wǎng)上找的很多教程都不怎么靠譜,給我挖了很多坑,所以希望我的這篇教程可以幫助你,少走點(diǎn)彎路,快速掌握這技術(shù),代碼的下載地址在文章開頭,記得npm install一下,就可以運(yùn)行了。如果這篇文章有幸?guī)椭侥?,希望讀者大大們可以給作者給個(gè)三連呀??????????????????文章來源地址http://www.zghlxwxcb.cn/news/detail-737730.html
到了這里,關(guān)于Vue實(shí)現(xiàn)動(dòng)態(tài)路由的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!