路由到另外一个页面_一个简单的Vue按钮级权限方案
在年初開發一個中后臺管理系統,功能涉及到了各個部門(產品、客服、市場等等),在開始的版本中,我和后端配合使用了花褲衩手摸手系列的權限方案,前期非常nice,但是慢慢的隨著功能增多、業務越來越復雜,就變得有些吃力了,因為我們的權限動態性太大了
為了解決上面2個痛點,我將原方案進行了一丟丟改造。
后端的配合:
有一些注意點:
實現
操作列表示例
以Restful風格接口為例
路由的變化
在路由的meta中增加一個配置字段如requireOps,值可能為String或者Array,這表示當前路由頁面要顯示的必要的操作碼,Array類型是為了處理一個路由頁面需要滿足同時存在多個操作權限時才顯示的情況。若值不為這2種則視為無權限控制,任何用戶都能訪問
由于最終需要根據過濾后的權限路由動態生成菜單,所以還需要在路由選項中增加幾個字段處理顯示問題,其中hidden優先級大于visible
由于路由在前端維護,所以以上配置只能寫死,如果后端能同意維護這一份路由表,那就可以有很多的發揮空間了,體驗也能做的更好。
權限路由過濾
先將權限路由規范一下,同時保留一個副本,可能在可視化時需要用到
獲取到操作列表后,只需要遍歷權限路由,然后查詢requireOps代表的操作有沒有在操作列表中。這里需要處理一下requireOps未設置的情況,如果子路由中都是權限路由,需要為父級路由自動加上requireOps值,不然當所有子路由都沒有權限時,父級路由就被認為是無權限控制且可訪問的;而如果子路由中只要有一個路由無權限控制,那就不需要處理父路由。所以這里可以用遞歸來解決,先處理子路由再處理父路由
const filterPermissionRoutes = (routes, cb) => {// 可能父路由沒有設置requireOps 需要根據子路由確定父路由的requireOpsroutes.forEach(route => {if (route.children) {route.children = filterPermissionRoutes(route.children, cb)if (!route.meta.requireOps) {const hasNoPermission = route.children.some(child => child.meta.requireOps === null)// 如果子路由中存在不需要權限控制的路由,則跳過if (!hasNoPermission) {route.meta.requireOps = [].concat(...route.children.map(child => child.meta.requireOps))}}}})return cb(routes) }然后根據操作列表對權限路由進行過濾
let operations = null // 從后端獲取后更新它 const hasOp = opcode => operations? operations.some(op => op.opcode === opcode): falseconst proutes = filterPermissionRoutes(permissionRoutes, routes => routes.filter(route => {const requireOps = route.meta.requireOpsif (requireOps) {return requireOps.some(hasOp)}return true }))// 動態添加路由 router.addRoutes(proutes)函數式組件控制局部權限
這個組件實現很簡單,根據傳入的操作碼進行權限判斷,若通過則返回插槽內容,否則返回null。另外,為了統一風格,支持一下root屬性,表示組件的根節點
const AccessControl = {functional: true,render (h, { data, children }) {const attrs = data.attrs || {}// 如果是root,直接透傳if (attrs.root !== undefined) {return h(attrs.root || 'div', data, children)}if (!attrs.opcode) {return h('span', {style: {color: 'red',fontSize: '30px'}}, '請配置操作碼')}const opcodes = attrs.opcode.split(',')if (opcodes.some(hasOp)) {return children}return null} }動態生成權限菜單
以ElementUI為例,由于動態渲染需要進行遞歸,如果以文件組件的形式會多一層根組件,所以這里直接用render function簡單寫一個示例,可以根據自己的需求改造
// 權限菜單組件 export const PermissionMenuTree = {name: 'MenuTree',props: {routes: {type: Array,required: true},collapse: Boolean},render (h) {const createMenuTree = (routes, parentPath = '') => routes.map(route => {// hidden: 為true時當前菜單和子菜單都不顯示if (route.hidden === true) {return null}// 子路徑處理const fullPath = route.path.charAt(0) === '/' ? route.path : `${parentPath}/${route.path}`// visible: 為false時不顯示當前菜單,但顯示子菜單if (route.visible === false) {return createMenuTree(route.children, fullPath)}const title = route.meta.titleconst props = {index: fullPath,key: route.path}if (!route.children || route.children.length === 0) {return h('el-menu-item',{ props },[h('span', title)])}return h('el-submenu',{ props },[h('span', { slot: 'title' }, title),...createMenuTree(route.children, fullPath)])})return h('el-menu',{props: {collapse: this.collapse,router: true,defaultActive: this.$route.path}},createMenuTree(this.routes))} }接口的權限控制
我們一般用axios,這里只需要在axios封裝的基礎上加幾行代碼就可以了,axios封裝花樣多多,這里簡單示例
const ajax = axios.create(/* config */)export default {post (url, data, opcode, config = {}) {if (opcode && !hasOp(opcode)) {return Promise.reject(new Error('沒有操作權限'))}return ajax.post(url, data, { /* config */ ...config }).then(({ data }) => data)},// ... }到這里,這個方案差不多就完成了,權限配置的可視化可以根據操作列表中的routeName來做,將操作與權限路由一一對應,在demo中有一個簡單實現
原文鏈接:https://juejin.im/post/5dd2a8d1518825499543c772作者:前端小智
總結
以上是生活随笔為你收集整理的路由到另外一个页面_一个简单的Vue按钮级权限方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 明基灯有假货吗
- 下一篇: 电脑中毒了还有救吗电脑中毒了还有救吗蓝屏