【前言】
此實現方案基於vue框架,並需要依賴vue項目相關的庫,router、store等等;前端同學要與后端同學協商,常規是讓后端返回一個樹結構的菜單數據,並且將所有的涉及權限控制的頁面path給到后端,如果是按鈕,需要把所有的按鈕 code 碼統一下,這是前期工作,很重要。
首先,main.js 引入相關文件
import Vue from 'vue'; import App from './App.vue'; import router from '@/router'; import store from '@/store'; import '@/plugins/permission'; import '@/plugins/directives'; import '@/plugins/auth'; Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App) }).$mount('#app');
在main.js同目錄創建 plugins 文件,作為公共文件,在plugins 里創建 permission.js。
import router from @/router'; import store from '@/store'; import { hasMenuAuth } from '@/plugins/auth'; router.beforeEach(async (to, from, next) => { store.dispatch('auth/getAuthData'); // 校驗菜單權限 if (hasMenuAuth(to.path)) { next(); } else { next({ path: '/' }); } });
在store目錄里創建 auth.js ,getUserMenuList 為定義的接口 api
import { getUserMemuList } from @/api/auth';
/**
* 樹型數據轉列表
* @param {*} tree 樹型數據
* @param {*} childrenKey 子節點列表鍵
*/
const convertTreeToList = (tree, childrenKey = 'children') => {
if (!Array.isArray(tree)) return [];
// 所有的菜單集合
let list = [];
// 遞歸查找
let fn = data => {
let origin = data.slice(0);
list = list.concat(origin);
data.forEach(item => {
let children = item[childrenKey];
Array.isArray(children) && fn(children);
});
};
fn(tree);
return list;
};
const state = {
// 路由菜單權限
routeAuthList: {},
// 按鈕權限列表
authList: {}
}
};
const mutations = {
// 菜單權限列表
SET_ROUTE_AUTH_LIST(state, data) {
// 路由權限集合
let routeAuthList = {};
// 按鈕權限集合
let buttonAuthList = {};
data.map(item => {
// 將所有的 path 存入對象中
if (item.path) {
routeAuthList[item.path] = true;
}
// 將所有的 code 存入對象中
if (item.code) {
buttonAuthList[item.code] = true;
}
});
state.routeAuthList = routeAuthList;
state.authList = buttonAuthList;
},
};
const actions = {
// 獲取菜單列表
getAuthData({ commit }) {
return getUserMemuList().then(({ data }) => {
let list = convertTreeToList(data);
commit('SET_ROUTE_AUTH_LIST', list);
return data;
});
},
};
export default {
namespaced: true,
state,
mutations,
actions
};
這時,例如在頁面中打印,效果是這樣的



至此,已經將該用戶下所屬的權限拉取,並存儲在 store 里了,可以全局訪問使用。
前面 permission 文件里引用的 hasMenuAuth 方法,需要在 plugins 目錄中,創建 auth.js, 並定義下此方法。
import Vue from 'vue'; import store from '@/store'; /** * 校驗路由是否有權限 * @param {Array} path 權限 * @return {boolean} */ export function hasMenuAuth(path) { // 無權限配置無需校驗 if (!(path && path.length)) return true; const list = store.state.auth.routeAuthList; // 校驗是否有權限 let auth = list[path] ? true : false; return auth; } /** * 校驗按鈕是否有權限 * @param {*} list 權限配置 */ export function hasBtnAuth(list) { // 無權限配置,不校驗 if (!list || !list.length) return true; const authList = (store.getters && store.getters.authList) || {}; let hasPermission = false; // // 遍歷數組,如果有一個code碼存在,則返回true list.map(item => { if (authList[item]) hasPermission = true; }); return hasPermission; } // 掛在權限校驗方法 Vue.has = hasBtnAuth; Vue.prototype.$has = hasBtnAuth;
到此處,整個項目路由的攔截就實現了,但目前只攔截了 path,但有頁面的按鈕,雖然點擊后由於做了攔截,讓其跳到了默認頁。但按鈕的還是展示的,這時就需要用到 上面的 hasBtnAuth 方法了。
由於已經在vue實例上掛載了 $has,只需在 vue 組件中使用就好了,可以用在節點里,也可在方法里


當然按鈕的顯隱,還有進階版方法,那就是可以注冊個自定義指令,在 plugins 目錄下創建 directives.js 文件
/** * 按鈕權限指令 * 根據vuex下的auth模塊的authList按鈕code列表判斷權限 */ import Vue from 'vue'; import store from '@/store'; /** * 校驗是否有權限,無權限刪除dom節點 * @param {*} el dom元素 * @param {*} binding 綁定數據 */ function hasAuth(el, binding) { const { value } = binding; const authList = (store.getters && store.getters.authList) || []; if (value && value instanceof Array && value.length > 0) { const list = value; let hasPermission = false; // 遍歷數組,如果有一個code碼存在,則返回true list.map(item => { if (authList[item]) hasPermission = true; }); if (!hasPermission && value && value.length) { el.parentNode && el.parentNode.removeChild(el); } } } let auth = { inserted: hasAuth, update: hasAuth }; const install = function(Vue) { Vue.directive('auth', auth); }; Vue.use(install);
現在,使用起來更方便了

好了,具體實現方法就是這些,有些地方簡述了,但幾乎涉及的地方都涉及到了,歡迎指出不足,我也會補全
