<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
1、建立vueRouter,用公共路由範例化
2、建立需要根據許可權篩選的路由物件(在路由物件,新增必要的許可權判斷欄位)
3、登入完成,由後端配合返回當前使用者的許可權集合
4、篩選出有許可權的路由物件,利用vueRouter的addRoutes方法,生成完整路由
5、處理重新整理頁面導致vueRouter重新範例化導致路由物件不完善 (利用router.beforeEach導航守衛,,利用addRoutes()完善 路由物件 )
6、側邊導航欄相關程式碼
根據上面的順序
1、如下
Vue.use(Router) // 公共路由 export const publicRoutes = [ { path: '/', name: 'login', component: login, meta: { title: '登入' } } ] // 需要根據許可權篩選的路由 export const asyncRoutes = [ ...Home, ...Seting, ...CRM, { path: '*', component: login, meta: { hidden: true }, redirect: '/' } ] const vr = new Router({ mode: 'history', routes: publicRoutes })
2、以seting模組為例,role為判斷是的許可權欄位,角色有這個欄位對應的值就有當前頁面的許可權
import Layout from '@/views/layout/layout.vue' const account = r => require.ensure([], () => r(require('@/views/seting/account/account.vue')), 'seting'); const logs = r => require.ensure([], () => r(require('@/views/seting/logs/logs.vue')), 'seting'); const role = r => require.ensure([], () => r(require('@/views/seting/role/role.vue')), 'seting'); const Seting = [ { path: '/seting', component: Layout, redirect: '/seting/account', meta: { title: '系統設定', role: '123c6c6514d416472e640bc3f49297c550', icon: 'icon-xitong' }, children: [ { path: 'account', name: 'account', component: account, meta: { title: '賬號管理', role: '1325cdeb897cc7f8e951d647de9b1d8e11', } }, { path: 'logs', name: 'logs', component: logs, meta: { title: '紀錄檔管理', role: '14bfbb0337ad3e7e2c9fc101294c3fe645', } }, { path: 'role', name: 'role', component: role, meta: { title: '角色管理', role: '1559d1c05d15a0dce5549b8bf5a58c0cf9', } } ] } ] export default Seting
如果有一些詳情頁不需要在導航列表展示還可以新增欄位,在生成導航欄時去掉
eg:
{ path: 'addJoiner', name: 'addJoiner', component: addJoiner, meta: { hidden: true, // 隱藏欄位 title: '***詳情頁', role: '14bfbb0337ad3e7e2c9fc101294c3fe645', } },
3、登入獲取許可權集合和基本資訊
// 登入 login () { this.rememberPassword() this.$refs.form.validate((valid) => { if (valid) { this.loading = true let params = { login_name: this.form.user, password: this.form.password, code: this.form.yanzhenma, } this.$api.post('api/user/login', params).then(res => { if (res.err_code === 1) { // 把使用者的基本資訊儲存在vuex,中 this.$store.dispatch('setBaseInfo', res.data).then(() => { // 獲取有許可權的路由表,新增到路由 router.addRoutes(this.$store.getters.addRouters) this.$router.push({ name: 'home' }) }) } this.loading = false }) } })
部分vuex程式碼
如果不太理解,點選下面連結:
actions.js
// import api from '@/api' const actions = { setBaseInfo ({ commit }, data) { return new Promise(resolve => { commit('set_userInfo', data.userInfo) commit('set_token', data.token) commit('set_roles', data.menus) // 把基本資訊儲存在本地防止重新整理之後丟失 sessionStorage.setItem('baseInfo', JSON.stringify(data)) resolve() }) } } export default actions
mutations.js
const setStorage = (key, value) => { if (typeof (value) === 'object') { value = JSON.stringify(value) } sessionStorage.setItem(key, value) } /* * 避免重新整理之後vuex被重置,在sessionStorage做一個備份 */ const mutations = { set_userInfo (state, payload) { state.userInfo = payload setStorage('userInfo', payload) }, set_token (state, payload) { state.token = payload setStorage('token', payload) }, set_roles (state, payload) { state.roles = payload setStorage('roles', payload) }, set_breadcrumb (state, payload) { state.breadcrumb = payload setStorage('breadcrumb', payload)/* */ }, changeCollapsed (state, payload) { state.isCollapsed = payload } } export default mutations
getters.js
import createdRoutes from '@/utils/createdRoutes.js' import { asyncRoutes } from '@/router/index.js' let getStoryage = (item) => { let str = sessionStorage.getItem(item) return JSON.parse(str) } const getters = { get_userInfo: (state) => { return state.userInfo ? state.userInfo : getStoryage('userInfo') }, get_token: (state) => { return state.token ? state.token : sessionStorage.getItem('token') }, get_roles: (state) => { return state.roles.length ? state.roles : getStoryage('roles') }, addRouters: (state, getters) => { let routes = createdRoutes(asyncRoutes, getters.get_roles) return routes }, get_breadcrumb: (state, getters) => { return state.breadcrumb.length ? state.breadcrumb : getStoryage('getStoryage') } } export default getters;
4、核心的篩選需要許可權的路由方法:createdRoutes()
也就是3的getters,用到的方法,毫無保留奉上
/** * 判單當前的路由物件是否在登入人的許可權之內 * @param {Array} roles 許可權 * @param {Object} route 路由 */ function hasPermission (roles, route) { if (route.meta && route.meta.role) { // 路由需要許可權就要在許可權陣列裡面判斷 return roles.includes(route.meta.role) } else { // 不需要許可權就直接通過 return true } } /** * 根據介面獲取的許可權列表動態生成當前使用者的側邊導航欄,返回通過許可權驗證的路由陣列 * @param {Array} asyncRoutes 需要過濾的路由 * @param {Array} roles 許可權 */ function createdRoutes (asyncRoutes, roles) { const accessedRouters = asyncRoutes.filter(route => { if (hasPermission(roles, route)) { // 當前路由通過許可權驗證直接通過 if (route.children && route.children.length) { // 當前路由有子路由,就遞迴驗證 route.children = createdRoutes(route.children, roles) } return true } return false }) return accessedRouters } export default createdRoutes
5、處理重新整理帶來的問題
其實這裡的程式碼是連線1的,注意註釋
// 全域性的導航守衛 vr.beforeEach((to, from, next) => { // 重新整理頁面之後導致vue-router和vuex重置,路由丟失,利用的就是重新整理後vuex的state被重置判斷 if (to.name !== 'login' && !store.state.token) { // 避免直接不登陸進頁面 if (!sessionStorage.getItem('token')) { location.href = '/' return } let data = JSON.parse(sessionStorage.getItem('baseInfo')) store.dispatch('setBaseInfo', data).then(() => { vr.addRoutes(store.getters.addRouters) }) } // 設定麵包屑導航 let breadcrumb = to.matched.filter(item => item.meta.title) if (breadcrumb.length) { breadcrumb = breadcrumb.map(item => item.meta.title) store.commit('set_breadcrumb', breadcrumb) } // 設定title document.title = to.meta.title next() })
6、側邊導航欄的完整程式碼
還是遍歷的根據許可權生成的路由表,幹掉一些需要隱藏的詳情頁之類,
這裡的程式碼和過濾l路由的核心函數,要根據自己的業務做相應的處理
element-ui的menu
<template> <el-menu class="el-menu-vertical-demo" :collapse="isCollapsed" background-color="#545c64" :default-active='activeIndex' text-color="#fff" active-text-color="#7EA8F5"> <section v-for="(item,index) in addRouters" :key="item.name" :class="isCollapsed ? 'collapsed':''"> <!-- 有子選單 --> <el-submenu :index=" `${index+1}`" v-if="!item.meta.hidden && item.children && item.children.length"> <template slot="title"> <i :class="`icon iconfont ${item.meta.icon}`"></i> <span slot="title">{{item.meta.title}}</span> </template> <section v-for="(item2,index2) in item.children" :key="item2.name"> <!-- 二級選單有子選單 --> <el-submenu :index="`${index+1}-${index2+1}`" v-if="item2.children && item2.children.length" class="sub2"> <template slot="title"> <span slot="title">{{item2.meta.title}}</span> </template> <!-- 三級選單 --> <el-menu-item v-for="(item3,index3) in item2.children" v-if="!item3.meta.hidden" :index="item3.name" :key="index3" @click.native="$router.push({name:item3.name})"> <span slot="title">{{item3.meta.title}}</span> </el-menu-item> </el-submenu> <!-- 二級選單無子選單 --> <!-- 不是隱藏的,詳情頁隱藏 --> <el-menu-item :index="item2.name" v-else-if="!item2.meta.hidden" @click.native="$router.push({name:item2.name})"> <span slot="title">{{item2.meta.title}}</span> </el-menu-item> </section> </el-submenu> <!-- 無子選單 --> <el-menu-item v-else-if="item.meta.hidden && item.children && item.children.length" :index="item.children[0].name" @click.native="$router.push({name:item.children[0].name})" class="item"> <i :class="`iconfont ${item.children[0].meta.icon}`"></i> <span slot="title">{{item.children[0].meta.title}}</span> </el-menu-item> </section> </el-menu> </template>
<script> import { mapGetters } from 'vuex' export default { props: { isCollapsed: { type: Boolean, default: false } }, computed: { ...mapGetters(['addRouters']), activeIndex () { //集火的選單 return this.$route.name } } } </script>
<style lang="scss" scoped> section { /deep/ .el-submenu__title { .icon { margin-right: 10px; } i { color: white; font-size: 14px; } } /deep/ .el-menu-item { padding-left: 50px !important; } /deep/ .el-menu-item.item { padding-left: 19px !important; i { color: white; font-size: 14px; margin-right: 12px; } } /deep/ .el-submenu .el-menu-item { min-width: 0; } /deep/ .el-submenu.sub2 .el-submenu__title { padding-left: 50px !important; i { margin-right: 0px; } } /* /deep/ .el-submenu.sub2 .el-menu-item { text-indent: 12px; } */ } .collapsed { width: 50px; /deep/ .el-submenu__title { .el-icon-arrow-right { display: none; } span[slot="title"] { display: none; } } } </style>
路由圖
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45