国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答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
主站蜘蛛池模板: 影音先锋亚洲综合小说在线 | 欧美日韩精品一区二区在线播放 | 精品一区二区三区四区五区 | 成人一级片在线观看 | 国产69久久精品成人看小说 | 成人免费一级毛片在线播放视频 | 亚洲综合欧美日本另类激情 | 成人午夜精品久久久久久久小说 | 欧美日韩亚洲色图 | 亚洲综合图片小说区热久久 | 久久伊人中文字幕有码 | 成人日韩在线 | 国产精品亚洲精品日韩动图 | 日韩亚洲欧美一区 | 日韩一级精品久久久久 | 国内精品视频一区二区三区 | 一区二区三区四区免费视频 | 精品国产欧美一区二区 | 国产精选在线观看 | 国产日韩欧美亚洲综合首页 | 日韩精品一区在线 | 欧美日韩亚洲第一页 | 激情午夜婷婷 | 亚洲一区二区三区久久精品 | 免费国产黄网站在线观看视频 | 国产毛片一级 | 久久免费福利视频 | 国产精品视频大全 | 亚洲国产成人久久一区www | 人人草视频在线观看 | 亚洲欧美在线视频 | 成人精品一区二区三区 | 日韩免费在线 | 亚洲高清一区二区三区 | 国产精品资源在线观看 | 国产精品专区第二 | 亚洲精品午夜国产va久久成人 | 欧美日韩中字 | 精品国产欧美一区二区 | 另类日韩| a国产|