vue-router+vuex addRoutes實(shí)現(xiàn)路由動(dòng)態(tài)加載及菜單動(dòng)態(tài)加載
此案例主要實(shí)現(xiàn)了一個(gè)功能是,在vue實(shí)例首次運(yùn)行時(shí),在加載了login和404兩個(gè)路由規(guī)則,登錄成功后,根據(jù)登錄用戶(hù)角色權(quán)限獲取該角色相應(yīng)菜單權(quán)限,生成新的路由規(guī)則添加進(jìn)去。
做過(guò)后臺(tái)管理系統(tǒng)都一定做過(guò)這個(gè)功能,在對(duì)菜單權(quán)限進(jìn)行粗粒度權(quán)限控制的時(shí)候,通過(guò)角色獲取菜單后,異步生成菜單,所以一開(kāi)始拿到需求的時(shí)候,我也以為這和平常的沒(méi)什么不同,不過(guò)做起來(lái)就發(fā)現(xiàn)了很多問(wèn)題,
1.vue-router的實(shí)例,在new vue實(shí)例的時(shí)候,就加載了,且必須加載,這個(gè)時(shí)候,登錄路由一定要加載,可是這個(gè)時(shí)候沒(méi)有登錄,無(wú)法確定權(quán)限
2.路由規(guī)則與菜單的同步
解決思路演化,菜單和路由同步,肯定是采用了vuex,一開(kāi)始的思路的是,在一開(kāi)始,就把所有的路由規(guī)則加載,然后在登錄的時(shí)候,取得權(quán)限路由,對(duì)比兩個(gè)路由,通過(guò)修改修改一個(gè)權(quán)限字段來(lái)隱藏菜單,如果在后臺(tái)頁(yè)面添加了新菜單規(guī)則,路由是按模塊加載的不同的文件,這時(shí)對(duì)路由的文件進(jìn)行新的讀寫(xiě),雖然可以解決問(wèn)題,但是如果手動(dòng)在瀏覽器地址上路由,依然可以訪(fǎng)問(wèn),所以在路由的全局鉤子上還要做攔截。
這個(gè)解決方案雖然解決,但是顯的比較復(fù)雜,于是就想需找新的方法,重新瀏覽官方api,發(fā)現(xiàn)在2.2.0以后,官方新增了api,addRoutes,專(zhuān)門(mén)針對(duì)服務(wù)端渲染路由,那么這下問(wèn)題就比較簡(jiǎn)單了,下面列出實(shí)現(xiàn)代碼。以下代碼不能直接復(fù)用,需要根據(jù)實(shí)際情況修改,只是提供思路
app.js
let permission = JSON.parse(window.sessionStorage.getItem('permission')) if (permission) { store.commit(ADD_MENU, permission) router.addRoutes(store.state.menu.items) } router.beforeEach((route, redirect, next) => { if (state.app.device.isMobile && state.app.sidebar.opened) { store.commit(TOGGLE_SIDEBAR, false) } if (route.path === '/login') { window.sessionStorage.removeItem('user') window.sessionStorage.removeItem('permission') store.commit(ADD_MENU, []) } let user = JSON.parse(window.sessionStorage.getItem('user')) if (!user && route.path !== '/login') { next({ path: '/login' }) } else { if (route.name) { next() } else { next({ path: '/nofound' }) } } })
登錄的組件login.vue
<template> <el-form :model="ruleForm2" :rules="rules2" ref="ruleForm2" label-position="left" label-width="0px" class="demo-ruleForm login-container"> <h3 class="title">系統(tǒng)登錄</h3> <el-form-item prop="account"> <el-input type="text" v-model="ruleForm2.account" auto-complete="off" placeholder="賬號(hào)"></el-input> </el-form-item> <el-form-item prop="checkPass"> <el-input type="password" v-model="ruleForm2.checkPass" auto-complete="off" placeholder="密碼"></el-input> </el-form-item> <el-checkbox v-model="checked" checked class="remember">記住密碼</el-checkbox> <el-form-item style="width:100%;"> <el-button type="primary" style="width:100%;" @click.native.prevent="handleSubmit2" :loading="logining">登錄 </el-button> <!--<el-button @click.native.prevent="handleReset2">重置</el-button>--> </el-form-item> </el-form> </template> <script> import NProgress from 'nprogress' import { mapActions, mapGetters } from 'vuex' export default { data () { return { logining: false, ruleForm2: { account: 'admin', checkPass: '123456' }, rules2: { account: [ {required: true, message: '請(qǐng)輸入賬號(hào)', trigger: 'blur'} // { validator: validaePass } ], checkPass: [ {required: true, message: '請(qǐng)輸入密碼', trigger: 'blur'} // { validator: validaePass2 } ] }, checked: true } }, computed: { ...mapGetters([ 'menuitems', 'isLoadRoutes' // ... ]) }, methods: { handleReset2 () { this.$refs.ruleForm2.resetFields() }, handleSubmit2 (ev) { this.$refs.ruleForm2.validate((valid) => { if (valid) { this.logining = true NProgress.start() let loginParams = {loginName: this.ruleForm2.account, password: this.ruleForm2.checkPass} this.$http.post('/api/privilege/user/login', loginParams).then(resp => { this.logining = false NProgress.done() let {message, data} = resp.data if (message === 'fail') { this.$notify({ title: '錯(cuò)誤', message: message, type: 'error' }) } else { window.sessionStorage.setItem('user', JSON.stringify(data.user)) window.sessionStorage.setItem('permission', JSON.stringify(data.permission)) this.addMenu(data.permission) if (!this.isLoadRoutes) { this.$router.addRoutes(this.menuitems) this.loadRoutes() } this.$router.push('/system/office') } }) } else { console.log('error submit!!') return false } }) }, ...mapActions([ 'addMenu', 'loadRoutes' ]) } } </script> <style lang="scss" scoped> .login-container { /*box-shadow: 0 0px 8px 0 rgba(0, 0, 0, 0.06), 0 1px 0px 0 rgba(0, 0, 0, 0.02);*/ -webkit-border-radius: 5px; border-radius: 5px; -moz-border-radius: 5px; background-clip: padding-box; margin-bottom: 20px; background-color: #F9FAFC; margin: 180px auto; border: 2px solid #8492A6; width: 350px; padding: 35px 35px 15px 35px; .title { margin: 0px auto 40px auto; text-align: center; color: #505458; } .remember { margin: 0px 0px 35px 0px; } } </style>
關(guān)鍵點(diǎn)解釋
computed: { ...mapGetters([ 'menuitems', 'isLoadRoutes' // ... ]) },
這里是從vuex取得兩個(gè)對(duì)象,menuitems是菜單對(duì)象,isLoadRoutes是用來(lái)判斷是否是第一次登錄,用來(lái)排除重復(fù)加載路由規(guī)則
...mapActions([ 'addMenu', 'loadRoutes' ])
這里是從vuex取得兩個(gè)方法,一個(gè)是添加菜單,一個(gè)更改loadRoutes的值
this.$router.addRoutes(this.menuitems)
這是關(guān)鍵api,動(dòng)態(tài)的向router實(shí)例中添加路由規(guī)則
menu模塊的state與mutations
const state = { items: [ ], isLoadRoutes: false } const mutations = { [types.EXPAND_MENU] (state, menuItem) { if (menuItem.index > -1) { if (state.items[menuItem.index] && state.items[menuItem.index].meta) { state.items[menuItem.index].meta.expanded = menuItem.expanded } } else if (menuItem.item && 'expanded' in menuItem.item.meta) { menuItem.item.meta.expanded = menuItem.expanded } }, [types.ADD_MENU] (state, menuItems) { if (menuItems.length === 0) { state.items = [] } else { generateMenuItems(state.items, menuItems) } }, [types.LOAD_ROUTES] (state) { state.isLoadRoutes = !state.isLoadRoutes } }
路由配置文件router.js
import Vue from 'vue' import Router from 'vue-router' import menuModule from 'vuex-store/modules/menu' Vue.use(Router) export default new Router({ mode: 'hash', // Demo is living in GitHub.io, so required! linkActiveClass: 'is-active', scrollBehavior: () => ({ y: 0 }), routes: [ { path: '/login', component: require('../Login.vue'), meta: { expanded: false, show: false }, name: 'Login' }, { path: '/', component: require('../views/Home.vue'), meta: { expanded: false, show: false }, children: [ { path: '/nofound', component: require('../404.vue'), name: 'NOFOUND', meta: {show: false} } ] }, ...generateRoutesFromMenu(menuModule.state.items) ] }) // Menu should have 2 levels. function generateRoutesFromMenu (menu = [], routes = []) { for (let i = 0, l = menu.length; i < l; i++) { let item = menu[i] if (item.path) { routes.push(item) } } return routes }
vuex
import Vue from 'vue' import Vuex from 'vuex' import * as actions from './actions' import * as getters from './getters' import menu from './modules/menu' Vue.use(Vuex) const store = new Vuex.Store({ strict: true, // process.env.NODE_ENV !== 'development', actions, getters, modules: { menu }, mutations: { } }) export default store
actions
export const addMenu = ({ commit }, menuItems) => { if (menuItems.length > 0) { commit(types.ADD_MENU, menuItems) } } export const loadRoutes = ({ commit }) => { commit(types.LOAD_ROUTES) }
getters
const menuitems = state => state.menu.items const isLoadRoutes = state => state.menu.isLoadRoutes export { menuitems, isLoadRoutes }
mutations_type.js
export const ADD_MENU = 'ADD_MENU' export const LOAD_ROUTES = 'LOAD_ROUTES'
因?yàn)樯厦娴拇a不能直接運(yùn)行,再次梳理一下思路,
1.創(chuàng)建vue實(shí)例的時(shí)候,將vuex和vue-router加載,這個(gè)時(shí)候,vue-router只有登錄規(guī)則和404規(guī)則
2.vuex中state管理的狀態(tài)對(duì)象有,菜單對(duì)象menuitems,是否加載過(guò)路由loadRoutes ,并提供相應(yīng)的getters與actions當(dāng)然還有一些其他的,這里沒(méi)有列舉
3.然后在登錄組件中,登錄成功后,將服務(wù)端傳回來(lái)之后,調(diào)用actions更改state.menuitems,并且中間有格式化的過(guò)程,這個(gè)過(guò)程的代碼沒(méi)有貼出來(lái),主要是由于不同的表涉和服務(wù)端返回的數(shù)據(jù)不一樣,,
4.然后調(diào)用addRoutes和actions更改已經(jīng)加載過(guò)路由的方法
5.然后為了防止用戶(hù)直接手動(dòng)按f5刷新頁(yè)面,這個(gè)時(shí)候會(huì)重新構(gòu)建vue實(shí)例,而又沒(méi)有重新登錄,所以vuex里面的東西會(huì)清空,所以將登錄后的數(shù)據(jù)存放在sessionStroage中,在刷新頁(yè)面,重新構(gòu)建vue實(shí)例的時(shí)候,會(huì)有判斷
6.之后會(huì)渲染側(cè)邊欄組件,列出菜單,數(shù)據(jù)就可以根據(jù)state.menuitems來(lái)就可以了,我這里沒(méi)有貼我的,實(shí)際根據(jù)自己的需求來(lái)
后面有時(shí)間會(huì)在github上上傳完整代碼。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue使用動(dòng)態(tài)添加路由(router.addRoutes)加載權(quán)限側(cè)邊欄的方式
- vue 解決addRoutes多次添加路由重復(fù)的操作
- vue addRoutes路由動(dòng)態(tài)加載操作
- 使用VueRouter的addRoutes方法實(shí)現(xiàn)動(dòng)態(tài)添加用戶(hù)的權(quán)限路由
- vue動(dòng)態(tài)添加路由addRoutes之不能將動(dòng)態(tài)路由存入緩存的解決
- vue 解決addRoutes動(dòng)態(tài)添加路由后刷新失效問(wèn)題
- vue addRoutes實(shí)現(xiàn)動(dòng)態(tài)權(quán)限路由菜單的示例
- vue-router4動(dòng)態(tài)路由刷新404/白屏的解決
- vue訪(fǎng)問(wèn)未定義的路由時(shí)重定向404問(wèn)題
- vue3動(dòng)態(tài)路由刷新后空白或者404問(wèn)題的解決
- vue 項(xiàng)目中當(dāng)訪(fǎng)問(wèn)路由不存在的時(shí)候默認(rèn)訪(fǎng)問(wèn)404頁(yè)面操作
- vue?使用addRoutes動(dòng)態(tài)添加路由及刷新頁(yè)面跳轉(zhuǎn)404路由的問(wèn)題解決方案
相關(guān)文章
一文詳解Vue3中簡(jiǎn)單diff算法的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹Vue3中簡(jiǎn)單diff算法的實(shí)現(xiàn)與使用,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下2022-09-09vue?請(qǐng)求后端數(shù)據(jù)的示例代碼
在vue中,我們?nèi)绾瓮ㄟ^(guò)請(qǐng)求接口來(lái)訪(fǎng)問(wèn)后端的數(shù)據(jù)呢?在這里簡(jiǎn)單總結(jié)了一個(gè)小示例,對(duì)vue請(qǐng)求后端數(shù)據(jù)實(shí)例代碼感興趣的朋友一起看看吧2022-09-09Vue手動(dòng)控制點(diǎn)擊事件Click觸發(fā)方式
這篇文章主要介紹了Vue手動(dòng)控制點(diǎn)擊事件Click觸發(fā)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01用vue2.0實(shí)現(xiàn)點(diǎn)擊選中active其他選項(xiàng)互斥的效果
這篇文章主要介紹了用vue2.0實(shí)現(xiàn)點(diǎn)擊選中active其他選項(xiàng)互斥的效果,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Vue?Steam同款登錄驗(yàn)證數(shù)字輸入框功能
這篇文章主要介紹了Vue?Steam同款登錄驗(yàn)證數(shù)字輸入框功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03在VUE3中禁止網(wǎng)頁(yè)返回到上一頁(yè)的方法
這篇文章主要介紹了在VUE3中如何禁止網(wǎng)頁(yè)返回到上一頁(yè),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09vue+echarts繪制省份地圖并添加自定義標(biāo)注方式
這篇文章主要介紹了vue+echarts繪制省份地圖并添加自定義標(biāo)注方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04詳解在vue使用weixin-js-sdk常見(jiàn)使用方法
這篇文章主要介紹了 詳解在vue使用weixin-js-sdk常見(jiàn)使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05VUE2響應(yīng)式原理使用Object.defineProperty缺點(diǎn)
這篇文章主要為大家介紹了VUE2響應(yīng)式原理使用Object.defineProperty缺點(diǎn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Vuex給state中的對(duì)象新添加屬性遇到的問(wèn)題及解決
這篇文章主要介紹了Vuex給state中的對(duì)象新添加屬性遇到的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01