根據(jù)登錄狀態(tài)和用戶的角色設(shè)置路由攔截是控制臺(tái)的基本功能,本文主要是對(duì)這部分內(nèi)容的總結(jié)趣些,閱讀這篇文章之后瞬沦,你可以構(gòu)建一個(gè)基本功能完整的控制臺(tái)朱躺。
路由守衛(wèi)
登錄狀態(tài)的處理
用戶未登錄時(shí),攔截用戶的所有路由壳炎,跳轉(zhuǎn)登錄頁(yè)面泞歉,而在登錄之后,用戶不應(yīng)該再進(jìn)入登錄頁(yè)面匿辩,將頁(yè)面重定向到首頁(yè)
Const whiteList = [‘/login’] // 使用白名單放置不登錄也可以訪問的頁(yè)面腰耙,現(xiàn)在只有登錄頁(yè)
router.beforeEach((to, from, next) => {
const hasToken = getToken()
if (hasToken) {
if (to.path === ‘/login’) {
next({ path: ‘/‘ })
} else {
next()
}
} else {
if (whiteList) {
if (whiteList.includes(to.path)) {
next()
} else {
next('/login')
}
}
}
})
用戶角色的處理
一般我們項(xiàng)目中不但要根據(jù)用戶的登錄狀態(tài)限制路由,也存在根據(jù)用戶角色限制路由的場(chǎng)景铲球。
首先要在路由的meta中設(shè)置roles屬性沟优,roles設(shè)置為進(jìn)入路由需要的用戶角色,然后再在路由跳轉(zhuǎn)時(shí)睬辐,添加用戶角色的處理邏輯:
const needRoles = to.meta && to.meta.roles && to.meta.roles.length > 0
if (needRoles) {
const hasRoles = store.state.user.roles.some(role => to.meta.roles.includes(role))
if (hasRoles) {
next()
} else {
next('/403')
}
} else {
next()
}
菜單欄實(shí)現(xiàn)
不同角色的用戶登錄控制臺(tái)挠阁,因?yàn)榻巧珦碛械臋?quán)限不同我們應(yīng)該展示給用戶不同的菜單,在實(shí)現(xiàn)路由守衛(wèi)的時(shí)候溯饵,我們?cè)诼酚傻膍eta上通過設(shè)置roles屬性限制了不同角色的權(quán)限侵俗,這個(gè)權(quán)限的限制與菜單欄的顯示權(quán)限的限制應(yīng)該是一致的。所以我們可以使用路由和獲取的用戶角色來生成菜單欄菜單丰刊。
/**
* 根據(jù)路由meta.role確定是否當(dāng)前用戶擁有訪問權(quán)限
* @roles 用戶擁有角色
* @route 待判定路由
*/
function hasPermission (roles, route) {
// 如果當(dāng)前路由有roles字段則需判斷用戶訪問權(quán)限
if (route.meta && route.meta.roles) {
// 若用戶擁有的角色中有被包含在待判定路由角色表中的則擁有訪問權(quán)
return roles.some(role => route.meta.roles.includes(role))
} else {
// 沒有設(shè)置roles則無需判定即可訪問
return true
}
}
/**
* 遞歸過濾AsyncRoutes路由表
* @routes 待過濾路由表隘谣,首次傳入的就是AsyncRoutes
* @roles 用戶擁有角色
*/
export function filterAsyncRoutes (routes, roles) {
const res = []
routes.forEach(route => {
// 復(fù)制一份
const tmp = { ...route }
// 如果用戶有訪問權(quán)則加入結(jié)果路由表
if (hasPermission(roles, tmp)) {
// 如果存在子路由則遞歸過濾之
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
filterAsyncRoutes(asyncRoutes, state.roles)
我們使用roles過濾生成新的路由后會(huì)發(fā)現(xiàn),生成的路由直接作為菜單項(xiàng)還是存在一些問題啄巧,例如數(shù)據(jù)詳情頁(yè)面往往是不在菜單欄中展示的寻歧,所以過濾后的路由直接作為菜單項(xiàng)依舊不是很合適,所以需要再進(jìn)行處理秩仆,通過路由的hidden屬性再次進(jìn)行過濾码泛。
const filterMenu = (route) => {
const children = route.children ? route.children.filter(item => !item.hidden) : []
if (children.length === 0) {
return {
icon: route.meta.icon, name: route.name, title: route.meta.title
}
}
if (children.length === 1) {
// 單只有一個(gè)子菜單的時(shí)候,子菜單會(huì)被提升
return filterMenu(children[0])
}
if (children.length > 1) {
return {
icon: route.meta.icon, name: route.name, title: route.meta.title, subs: children.map(filterMenu)
}
}
}
請(qǐng)求處理
發(fā)送請(qǐng)求也是項(xiàng)目中必不可少的的功能澄耍,在項(xiàng)目中我們通常使用axios來發(fā)送請(qǐng)求噪珊,針對(duì)請(qǐng)求我們?cè)谡?qǐng)求發(fā)送之前和接受請(qǐng)求時(shí)進(jìn)行處理晌缘。
http.interceptors.request.use(
config => {
config.headers['token'] = getToken()
return config
},
error => {
return Promise.reject(error)
}
)
http.interceptors.response.use(
response => {
if (response.status !== 200) {
return Promise.reject(response)
}
// 處理狀態(tài)碼
const data = response.data
if (data.code === 10000) {
// setToken(cookies)
return data
}
// 1006為用戶未登錄
if (data.code === 10006) {
MessageBox.alert('登錄狀態(tài)異常,請(qǐng)重新登錄', '確認(rèn)登錄信息', {
confirmButtonText: '重新登錄',
type: 'warning',
callback: () => {
removeToken()
router.replace({ name: 'login' })
}
})
return Promise.reject(new Error(data))
}
// 其他錯(cuò)誤碼痢站,提示信息并返回信息
Message({
message: data,
type: 'error',
duration: 3 * 1000
})
return Promise.reject(new Error(data))
},
error => {
Message({
message: error.message,
type: 'error',
duration: 3 * 1000
})
return Promise.reject(error)
}
)
這里主要是對(duì)返回的結(jié)果進(jìn)行處理磷箕,根據(jù)不同的錯(cuò)誤類型進(jìn)行分類處理,比較要代表性的是登錄狀態(tài)失效的處理阵难,和其他錯(cuò)誤不同岳枷,登錄失效會(huì)直接讓用戶進(jìn)入登錄頁(yè)面。
其他
- 菜單欄的收起與展開:在store的state中添加collapse進(jìn)行控制呜叫,在Header組件中根據(jù)頁(yè)面寬度進(jìn)行collapse的初始設(shè)置嫩舟。
if (document.body.clientWidth < 980) {
this.$store.commit('changeCollapse', true)
}
- 標(biāo)簽頁(yè)的控制:標(biāo)簽頁(yè)的標(biāo)簽頁(yè)列表也放到store中,這樣用戶在頁(yè)面里需要關(guān)閉標(biāo)簽頁(yè)時(shí)怀偷,就可以調(diào)用方法進(jìn)行關(guān)閉了家厌。