這次帶給大家怎麼使用vue addRoutes實作動態權限路由選單,怎麼使用vue addRoutes實作動態權限路由選單的注意事項有哪些,以下就是實戰案例,一起來看一下。
需求
最近接手一個後台管理系統,需要實現導航選單從後台拉取的效果;根據登入使用者的權限不同分別拉出來的導航選單也不一樣,另外可操作的介面也存在差異。
問題
因為後台管理系統是準備使用vue vue-router element-ui vuex的搭配來做的,可是單頁應用在進入頁面之前就已經將vue-router實例化並且注入vue實例中了,所以在進入登錄頁面的時候舊沒辦法在重新定制路由了。接下來各種百之谷之,發現vue-router在2.0版本中提供了addRoutes方法加入路由,希望的曙光出現。
經過一番折騰終於實現了功能,記錄下來便於回顧,也希望能幫助到同樣有需求的同志。
思路
1、首先在本地配置好固定不變的路由位址,例如登錄,404這些頁面,如下:
import Vue from 'vue' import Router from 'vue-router' import store from '@/vuex/store' Vue.use(Router) let router = new Router({ routes: [ { path: '/login', name: 'login', meta: {requireAuth: false}, // 模块使用异步加载 component: (resolve) => require(['../components/login/login.vue'], resolve) }] }) // 拦截登录,token验证 router.beforeEach((to, from, next) => { if (to.meta.requireAuth === undefined) { if (store.state.token) { next() } else { next({ path: '/login' }) } } else { next() } }) export default router
配置好這些固定的路由後我們才能夠到登入頁面,不然是無法繼續下去的。
2、然後重要的一步,我們需要跟後端老鐵約定好需要返回的權限選單列表資訊;首先這裡我們先分析一下自己需要的路由結構,這裡以我自己的路由作為例子。如果是我自己直接定義路由的話,會是以下結構:
let router = new Router({ routes: [ { path: '/login', name: 'login', meta: {requireAuth: false}, component: (resolve) => require(['../components/login/login.vue'], resolve) }, { path: '/', redirect: '/layout' }, { path: '/layout', component: (resolve) => require(['../layout.vue'], resolve), children: [ { path: 'index', meta: { type: '1', //控制是否显示隐藏 1显示,2隐藏 code: 00010001, // 后面需要控制路由高亮 title: '首页', // 菜单名称 permissonList: [] // 权限列表 } component: (resolve) => require(['@/components/index/index.vue'], resolve) }, { ... } ] }] })
根據以上結構分析,其實真正需要動態配置的路由其實是/layout下面的children部分,所以需要後端回傳給我們包含所有路由的一個數組就可以了
返回的資料中rootList中是一級導航的列表,一級導航實際上是沒有路由功能,只是作為切換二級選單的觸發器,subList才是我們真正需要的路由資訊。
3、拿到權限路由資訊後,需要我們在本地對資料進行處理組裝成我們需要的資料:
// 登录 login () { let params = { account: this.loginForm.username, password: encrypt(this.loginForm.password) } this.loading = true this.$http.post(this.$bumng + '/login', this.$HP(params)) .then((res) => { this.loging = false console.info('菜单列表:', res) if (res.resultCode === this.$state_ok) { // 合并一级菜单和二级菜单,便于显示 let menus = handleMenu.mergeSubInRoot(res.rootList, res.subList) // 本地化处理好的菜单列表 this.saveRes({label: 'menuList', value: menus}) // 根据subList处理路由 let routes = handleMenu.mergeRoutes(res.subList) // 本地化subList,便于在刷新页面的时候重新配置路由 this.saveRes({label: 'subList', value: res.subList}) // 防止重复配置相同路由 if (this.$router.options.routes.length <= 1) { this.$router.addRoutes(routes) // this.$router不是响应式的,所以手动将路由元注入路由对象 this.$router.options.routes.push(routes) } this.$router.replace('/layout/index') } }) .catch((err) => { this.loging = false console.error('错误:', err) }) },
處理選單列表和subList的方法:mergeSubInRoot 和mergeRoutes
const routes = [ { path: '/', redirect: '/layout' }, { path: '/layout', component: (resolve) => require(['../layout.vue'], resolve), children: [] } ] export default { /** * 合并主菜单和子菜单 * @param: rootList [Array] 主菜单列表 * @param: subList [Array] 子菜单 * */ mergeSubInRoot (roots, subs) { if (roots && subs) { for (let i = 0; i < roots.length; i++) { let rootCode = roots[i].code roots[i].children = [] for (let j = 0; j < subs.length; j++) { if (rootCode === subs[j].code.substring(0, 4)) { roots[i].children.push(subs[j]) } } } } return roots }, /** * 合并远程路由到本地路由 * @param: subList [Array] 远程路由列表 * @param: routes [Array] 本地路由列表 * */ mergeRoutes (subs) { if (subs) { for (let i = 0; i < subs.length; i++) { let temp = { path: subs[i].actUrl, name: subs[i].actUrl, component: (resolve) => require([`@/components/${subs[i].component}.vue`], resolve), meta: { type: subs[i].type, code: subs[i].code, title: subs[i].name, permissionList: subs[i].permissionList } } routes[1].children.push(temp) } } return routes } }
至此我們已經將權限路由成功配置進本機路由了,我的系統登入進入如下
##後續最佳化
1、選單清單的顯示以及二級導航切換:<template> <p class="mainMenu"> <el-menu class="menubar" mode="horizontal" :default-active="activeCode" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b"> <el-menu-item :index="item.code | splitCode" v-for="item in menuList" :key="item.code" @click="switchSubMenu(item)" v-if="item.code !== '0008'"> <i :class="`iconfont icon-${item.imgUrl}`"></i> <span slot="title">{{item.name}}</span> </el-menu-item> </el-menu> </p> </template> <script type="text/ecmascript-6"> import {mapState, mapMutations} from 'vuex' export default { name: 'menu', data () { return { msg: 'Welcome to Your Vue.js App' } }, computed: { ...mapState(['menuList']), activeCode () { // 通过code保证在切换字路由的情况下一级路由也是高亮显示 return this.$route.meta.code.substring(0, 4) } }, methods: { ...mapMutations(['saveRes']), // 切换二级路由 switchSubMenu (route) { console.info('路由:', route) if (route.actUrl !== 'index') { // 用currentSubMenu控制二级路由数据 this.saveRes({label: 'currentSubMenu', value: route.children}) this.$router.push(`/layout/${route.children[0].actUrl}`) } else { // 不存在二级路由隐藏二级 this.saveRes({label: 'currentSubMenu', value: ''}) this.$router.push(`/layout/${route.actUrl}`) } } }, filters: { splitCode (code) { return code.substring(0, 4) } } } </script>
<script> import {decrypt} from '@/libs/AES' import handleMenu from '@/router/handleMenu' export default { name: 'app', created () { // 当this.$router.options.routes的长度为1,且本地缓存存在菜单列表的时候才重新配置路由 if (this.$router.options.routes.length <= 1 && sessionStorage.getItem('subList')) { let subList = JSON.parse(decrypt(sessionStorage.getItem('subList'))) let routes = handleMenu.mergeRoutes(subList) this.$router.addRoutes(routes) // this.$router不是响应式的,所以手动将路由元注入路由对象 this.$router.options.routes.push(routes) } } } </script>
使用create-react-app建立React開發環境步奏詳解
以上是怎麼使用vue addRoutes實現動態權限路由選單的詳細內容。更多資訊請關注PHP中文網其他相關文章!