基于Vue3?+?TS?+?Ant?Design?Vue?實(shí)現(xiàn)精細(xì)化菜單按鈕權(quán)限授權(quán)組件功能
在前端開發(fā)中,RBAC(基于角色的訪問控制)是企業(yè)級(jí)應(yīng)用的核心需求。本文將分享如何使用 Vue3 + TypeScript + Vite + Ant Design Vue 實(shí)現(xiàn)一個(gè)功能完善的菜單與按鈕級(jí)別的權(quán)限授權(quán)組件,支持樹形菜單選擇、動(dòng)態(tài)按鈕聯(lián)動(dòng)、狀態(tài)持久化等高級(jí)特性。
?? 核心功能亮點(diǎn)
- ? 雙欄布局:左側(cè)樹形菜單選擇,右側(cè)動(dòng)態(tài)按鈕列表
- ? 細(xì)粒度控制:支持菜單級(jí)和按鈕級(jí)雙重權(quán)限控制
- ? 狀態(tài)保持:切換菜單時(shí)自動(dòng)保存/恢復(fù)按鈕選中狀態(tài)
- ? 父子聯(lián)動(dòng):自動(dòng)處理菜單的半選/全選狀態(tài)邏輯
- ? 類型安全:完整的 TypeScript 類型定義
- ? 性能優(yōu)化:使用 Map 緩存菜單數(shù)據(jù),避免重復(fù)查詢
?? 項(xiàng)目結(jié)構(gòu)概覽
src/
├── components/
│ └── MenuAuthModal.vue # 菜單授權(quán)彈窗組件
├── store/
│ └── index.ts # Vuex Store,管理全局按鈕權(quán)限
└── api/
└── contract.ts # 權(quán)限相關(guān) API 接口?? 核心技術(shù)實(shí)現(xiàn)
1. 組件架構(gòu)設(shè)計(jì)
采用 Ant Design Vue 的 Modal + Tree + Checkbox 組合,實(shí)現(xiàn)左右分欄布局:
<template>
<a-modal :visible="visible" width="960px">
<div class="menu-auth-content">
<!-- 標(biāo)題行 -->
<div class="header-row">
<div class="header-left">可授權(quán)菜單</div>
<div class="header-right">可授權(quán)按鈕</div>
</div>
<!-- 內(nèi)容區(qū)域 -->
<div class="content-row">
<!-- 左側(cè):樹形菜單 -->
<div class="content-left">
<a-tree
v-model:checkedKeys="checkedMenuKeys"
v-model:halfCheckedKeys="halfCheckedMenuKeys"
checkable
:tree-data="menuTreeData"
@select="onMenuSelect"
/>
</div>
<!-- 右側(cè):按鈕列表 -->
<div class="content-right">
<a-checkbox-group v-model:value="checkedButtons">
<div v-for="button in buttonList" :key="button.key">
<a-checkbox :value="button.key" :disabled="button.disabled">
{{ button.label }}
</a-checkbox>
</div>
</a-checkbox-group>
</div>
</div>
</div>
</a-modal>
</template>2. 狀態(tài)管理策略
使用 全局 Map 保存每個(gè)菜單的按鈕選中狀態(tài),解決切換菜單時(shí)狀態(tài)丟失問題:
// 全局按鈕選中狀態(tài)(菜單ID -> 按鈕ID數(shù)組)
const globalButtonStates = ref<Map<string, string[]>>(new Map())
// 監(jiān)聽按鈕變化,實(shí)時(shí)保存
watch(checkedButtons, (newValue) => {
if (isRestoringState.value) return // 避免恢復(fù)狀態(tài)時(shí)重復(fù)觸發(fā)
if (selectedMenuKeys.value.length > 0) {
const currentMenuId = selectedMenuKeys.value[0]
globalButtonStates.value.set(currentMenuId, [...newValue])
}
}, { deep: true })3. 菜單樹數(shù)據(jù)處理
將后端返回的嵌套菜單結(jié)構(gòu)轉(zhuǎn)換為 Ant Design Tree 所需格式:
const convertMenuTree = (menu: FindMenuButtonTreeByRoleInfo): any => {
return {
key: String(menu.id),
name: menu.name,
icon: menu.icon || '',
children: menu.children?.map(child => convertMenuTree(child)) || []
}
}4. 權(quán)限收集邏輯
提交時(shí)遞歸收集所有選中菜單(含父級(jí))和按鈕:
const collectAllMenuIdsWithParents = (): string[] => {
const allMenuIds = new Set<string>()
// 添加完全選中和半勾選的菜單
checkedMenuKeys.value.forEach(id => allMenuIds.add(id))
halfCheckedMenuKeys.value.forEach(id => allMenuIds.add(id))
// 遞歸查找所有父級(jí)菜單
checkedMenuKeys.value.forEach(menuId => {
const parentIds = findParentMenuIds(menuId)
parentIds.forEach(parentId => allMenuIds.add(parentId))
})
return Array.from(allMenuIds)
}5. 全局權(quán)限存儲(chǔ)
在 Vuex Store 中構(gòu)建按鈕權(quán)限映射表,供全局使用:
// store/index.ts
function buildButtonPermissionMap(menuList: MenuButtonTree[], buttonMap: Map<string, boolean>) {
menuList.forEach((menu: MenuButtonTree) => {
const menuKey = menu.active || (menu as any).key || ''
if (menuKey && menu.buttons) {
menu.buttons.forEach((button: any) => {
const buttonKey = `${menuKey}_${button.id}`
buttonMap.set(buttonKey, true)
})
}
menu.children?.forEach(child =>
buildButtonPermissionMap([child], buttonMap)
)
})
}
// Getter 用于權(quán)限判斷
hasButtonPermission: (state) => (menuActive: string, buttonId: number | string) => {
const buttonKey = `${menuActive}_${buttonId}`
return state.buttonPermissions.has(buttonKey)
}?? 使用示例
父組件調(diào)用
<template>
<a-button @click="openAuthModal">菜單授權(quán)</a-button>
<MenuAuthModal ref="authModalRef" @ok="handleAuthSuccess" />
</template>
<script setup lang="ts">
const authModalRef = ref()
const openAuthModal = () => {
authModalRef.value.open({
id: '123',
roleName: '超級(jí)管理員'
})
}
const handleAuthSuccess = ({ roleId, menuPermissions, buttonPermissions }) => {
console.log('授權(quán)成功', { roleId, menuPermissions, buttonPermissions })
// 刷新列表或更新狀態(tài)
}
</script>頁面按鈕權(quán)限控制
<template>
<a-button
v-if="$store.getters.hasButtonPermission('ContractList', 1001)"
@click="handleEdit"
>
編輯
</a-button>
</template>?? 樣式優(yōu)化
使用 Less 實(shí)現(xiàn)美觀的雙欄布局和滾動(dòng)條樣式:
.menu-auth-content {
.header-row {
display: flex;
border-bottom: 1px solid #f0f0f0;
.header-left {
width: 30%;
border-right: 1px solid #f0f0f0;
}
.header-right {
width: 70%;
}
}
.content-row {
display: flex;
.content-left, .content-right {
max-height: 500px;
overflow-y: auto;
}
.content-left {
width: 30%;
border-right: 1px solid #f0f0f0;
}
.content-right {
width: 70%;
.button-checkbox-item:nth-child(even) {
background: #FAFAFA;
}
}
}
}
// 自定義滾動(dòng)條
.content-left::-webkit-scrollbar {
width: 6px;
}
.content-left::-webkit-scrollbar-thumb {
background: #d9d9d9;
border-radius: 3px;
}?? 性能優(yōu)化技巧
- Map 緩存:使用
Map<string, Menu>快速查找菜單對(duì)象,避免 O(n) 遍歷 - 防抖處理:狀態(tài)恢復(fù)時(shí)使用
isRestoringState標(biāo)志位,防止 watch 重復(fù)觸發(fā) - 按需渲染:僅當(dāng)選中菜單時(shí)才加載對(duì)應(yīng)的按鈕列表
- 深度克隆:使用
[...array]避免引用導(dǎo)致的意外修改
?? 總結(jié)
本方案實(shí)現(xiàn)了企業(yè)級(jí)應(yīng)用所需的完整權(quán)限授權(quán)功能,具有以下優(yōu)勢(shì):
- 用戶體驗(yàn)佳:直觀的樹形選擇 + 實(shí)時(shí)按鈕預(yù)覽
- 代碼可維護(hù):清晰的職責(zé)分離,TypeScript 類型保障
- 擴(kuò)展性強(qiáng):易于添加新的權(quán)限維度(如數(shù)據(jù)權(quán)限)
- 性能優(yōu)秀:合理的緩存策略和狀態(tài)管理
通過本文的實(shí)現(xiàn),你可以快速在自己的項(xiàng)目中集成類似的權(quán)限管理系統(tǒng),提升應(yīng)用的安全性和靈活性。
到此這篇關(guān)于基于 Vue3 + TS + Ant Design Vue 實(shí)現(xiàn)精細(xì)化菜單按鈕權(quán)限授權(quán)組件的文章就介紹到這了,更多相關(guān)基于 Vue3 + TS + Ant Design Vue 實(shí)現(xiàn)精細(xì)化菜單按鈕權(quán)限授權(quán)組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue3使用watch監(jiān)聽props的值的注意事項(xiàng)及說明
這篇文章主要介紹了vue3使用watch監(jiān)聽props的值的注意事項(xiàng)及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06
詳解基于Vue2.0實(shí)現(xiàn)的移動(dòng)端彈窗(Alert, Confirm, Toast)組件
這篇文章主要介紹了詳解基于Vue2.0實(shí)現(xiàn)的移動(dòng)端彈窗(Alert, Confirm, Toast)組件,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
詳解用vue-cli來搭建vue項(xiàng)目和webpack
本篇文章主要介紹了詳解用vue-cli來搭建vue項(xiàng)目和webpack,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
vue項(xiàng)目中路由懶加載的三種方式(簡(jiǎn)潔易懂)
本文主要介紹了vue項(xiàng)目中路由懶加載的三種方式,主要包括vue異步組件,組件懶加載,webpack的require.ensure(),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01
解決vue js IOS H5focus無法自動(dòng)彈出鍵盤的問題
今天小編就為大家分享一篇解決vue js IOS H5focus無法自動(dòng)彈出鍵盤的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-08-08
vue.js實(shí)例todoList項(xiàng)目
本篇文章主要介紹了vue.js實(shí)例todoList項(xiàng)目,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07

