<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        vue-router+vuex addRoutes實現路由動態加載及菜單動態加載

        來源:懂視網 責編:小采 時間:2020-11-27 22:28:43
        文檔

        vue-router+vuex addRoutes實現路由動態加載及菜單動態加載

        vue-router+vuex addRoutes實現路由動態加載及菜單動態加載:此案例主要實現了一個功能是,在vue實例首次運行時,在加載了login和404兩個路由規則,登錄成功后,根據登錄用戶角色權限獲取該角色相應菜單權限,生成新的路由規則添加進去。 做過后臺管理系統都一定做過這個功能,在對菜單權限進行粗粒度權限控制的時候,通
        推薦度:
        導讀vue-router+vuex addRoutes實現路由動態加載及菜單動態加載:此案例主要實現了一個功能是,在vue實例首次運行時,在加載了login和404兩個路由規則,登錄成功后,根據登錄用戶角色權限獲取該角色相應菜單權限,生成新的路由規則添加進去。 做過后臺管理系統都一定做過這個功能,在對菜單權限進行粗粒度權限控制的時候,通

        此案例主要實現了一個功能是,在vue實例首次運行時,在加載了login和404兩個路由規則,登錄成功后,根據登錄用戶角色權限獲取該角色相應菜單權限,生成新的路由規則添加進去。

        做過后臺管理系統都一定做過這個功能,在對菜單權限進行粗粒度權限控制的時候,通過角色獲取菜單后,異步生成菜單,所以一開始拿到需求的時候,我也以為這和平常的沒什么不同,不過做起來就發現了很多問題,

        1.vue-router的實例,在new vue實例的時候,就加載了,且必須加載,這個時候,登錄路由一定要加載,可是這個時候沒有登錄,無法確定權限
        2.路由規則與菜單的同步

        解決思路演化,菜單和路由同步,肯定是采用了vuex,一開始的思路的是,在一開始,就把所有的路由規則加載,然后在登錄的時候,取得權限路由,對比兩個路由,通過修改修改一個權限字段來隱藏菜單,如果在后臺頁面添加了新菜單規則,路由是按模塊加載的不同的文件,這時對路由的文件進行新的讀寫,雖然可以解決問題,但是如果手動在瀏覽器地址上路由,依然可以訪問,所以在路由的全局鉤子上還要做攔截。

        這個解決方案雖然解決,但是顯的比較復雜,于是就想需找新的方法,重新瀏覽官方api,發現在2.2.0以后,官方新增了api,addRoutes,專門針對服務端渲染路由,那么這下問題就比較簡單了,下面列出實現代碼。以下代碼不能直接復用,需要根據實際情況修改,只是提供思路

        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">系統登錄</h3> 
         <el-form-item prop="account"> 
         <el-input type="text" v-model="ruleForm2.account" auto-complete="off" placeholder="賬號"></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: '請輸入賬號', trigger: 'blur'} 
         // { validator: validaePass } 
         ], 
         checkPass: [ 
         {required: true, message: '請輸入密碼', 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: '錯誤', 
         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> 

        關鍵點解釋

        computed: { 
         ...mapGetters([ 
         'menuitems', 
         'isLoadRoutes' 
         // ... 
         ]) 
         }, 

        這里是從vuex取得兩個對象,menuitems是菜單對象,isLoadRoutes是用來判斷是否是第一次登錄,用來排除重復加載路由規則

        ...mapActions([ 
         'addMenu', 
         'loadRoutes' 
         ]) 

        這里是從vuex取得兩個方法,一個是添加菜單,一個更改loadRoutes的值

        this.$router.addRoutes(this.menuitems) 

        這是關鍵api,動態的向router實例中添加路由規則

        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' 

        因為上面的代碼不能直接運行,再次梳理一下思路,

        1.創建vue實例的時候,將vuex和vue-router加載,這個時候,vue-router只有登錄規則和404規則

        2.vuex中state管理的狀態對象有,菜單對象menuitems,是否加載過路由loadRoutes ,并提供相應的getters與actions當然還有一些其他的,這里沒有列舉

        3.然后在登錄組件中,登錄成功后,將服務端傳回來之后,調用actions更改state.menuitems,并且中間有格式化的過程,這個過程的代碼沒有貼出來,主要是由于不同的表涉和服務端返回的數據不一樣,,

        4.然后調用addRoutes和actions更改已經加載過路由的方法

        5.然后為了防止用戶直接手動按f5刷新頁面,這個時候會重新構建vue實例,而又沒有重新登錄,所以vuex里面的東西會清空,所以將登錄后的數據存放在sessionStroage中,在刷新頁面,重新構建vue實例的時候,會有判斷

        6.之后會渲染側邊欄組件,列出菜單,數據就可以根據state.menuitems來就可以了,我這里沒有貼我的,實際根據自己的需求來

        后面有時間會在github上上傳完整代碼。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        vue-router+vuex addRoutes實現路由動態加載及菜單動態加載

        vue-router+vuex addRoutes實現路由動態加載及菜單動態加載:此案例主要實現了一個功能是,在vue實例首次運行時,在加載了login和404兩個路由規則,登錄成功后,根據登錄用戶角色權限獲取該角色相應菜單權限,生成新的路由規則添加進去。 做過后臺管理系統都一定做過這個功能,在對菜單權限進行粗粒度權限控制的時候,通
        推薦度:
        標簽: 加載 菜單 VUE
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 黄色网站软件app在线观看免费| 一级美国片免费看| 久久免费视频网站| 亚洲成AV人片在线观看ww| 色www永久免费网站| 亚洲AV无码国产精品色午友在线 | 亚洲精品无码久久毛片波多野吉衣 | 中国videos性高清免费| 亚洲日韩激情无码一区| 波霸在线精品视频免费观看| 亚洲午夜久久久影院伊人| 99re6在线视频精品免费| 亚洲国产精品SSS在线观看AV | 美女视频黄的全免费视频网站| 精品亚洲aⅴ在线观看| 亚洲黄色免费网站| 亚洲精品福利你懂| 在线观看免费国产视频| 人体大胆做受免费视频| 亚洲电影中文字幕| 成人免费毛片内射美女APP| 亚洲AV成人无码网站| 激情97综合亚洲色婷婷五 | 青青操视频在线免费观看| 亚洲A∨无码一区二区三区| 1000部啪啪毛片免费看| 亚洲性色AV日韩在线观看| 亚洲精品国产日韩无码AV永久免费网| jizz中国免费| 亚洲视频在线观看免费视频| 韩国18福利视频免费观看| 抽搐一进一出gif免费视频| 亚洲国产综合自在线另类| 国产成人免费片在线视频观看| 中文精品人人永久免费| 亚洲AV成人噜噜无码网站| 免费一区二区视频| 日韩精品人妻系列无码专区免费 | 欧美好看的免费电影在线观看| 黄色a级片免费看| 91亚洲导航深夜福利|