JS递归遍历查询权限:处理异构权限树结构的解决方案
本文介绍在基于qiankun的微前端项目中,针对层级结构中子菜单键名不一致(如children、functionList等)的权限树,设计并实现了一种基于do-while循环与递归思想结合的遍历算法。通过构建通用的查找模板findMap,利用数组filter方法逐层匹配,实现了对按钮级权限的高效查询,解决了传统递归难以应对异构数据结构的痛点。
前言
近期参与了一个基于qiankun构建的大型微前端项目,该项目包含十余个子应用。在此背景下,基座侧独立开发了一套完善的权限中心模块。该权限体系采用了“模块 > 一级菜单 > N级菜单/按钮”的多层结构进行权限管理。
本次任务聚焦于其中一个子应用的按钮级权限控制。在鉴权环节,编写了一个辅助方法,旨在从复杂的权限树中查询特定按钮是否存在于用户的权限列表中,以此决定用户是否拥有该按钮的操作权限。
需求分析
- 权限树中每一层级对应的子菜单键名并不统一。
- 业务逻辑需要从权限树中准确获取是否存在指定权限。
- 按钮级别的菜单名称可能存在重复情况。
设计思路
- 通过对权限树的分析有如下结论:
- 权限树的层级深度是有限的。
- 由于子菜单对应的键名不一致,部分节点使用children,部分使用functionList,还有部分使用menuList。
- 在同一层级内,菜单项不会重复。
- 设计一种可遍历的数据结构,并对该结构执行遍历查找操作。
- 若找到目标且数据结构一致则返回true,若在任意一级未找到则返回false。
代码
鉴于上述需求分析中提到的原因,传统的递归方法难以直接适用。因此,结合具体数据特征,构建了一种支持递归解决思路的数据结构。
此处采用do-while循环配合递归findMap模板的方式实现。之所以需要定义三个字段,是因为子菜单对应的键名各不相同。虽然理论上可以修改原始数据结构,但这会带来较大的改动成本和影响范围,因此采取当前方案。
声明查找模板如下
interface findItem {
findKey: string // 目标项的key
findVal: string // 目标项的value
childrenKey: string // 子菜单的key
}
// 查找模板
const findMap = [
{findkey: 'name', findVal: "模块A", childrenKey:'functionList'},
{findkey: 'functionName', findVal: '菜单1', childrenKey:'children'},
{findkey: 'functionName', findVal: '菜单1-1', childrenKey:'children'},
{findkey: 'functionName', findVal: '按钮1-1-3'}
]
接下来执行递归findItem[]逻辑。
循环体内的查找方法有多种选择,此处临时选用数组的filter方法。实际上,数组的其他方法(如some、include等)也能实现类似结果。
js版本
/**
* 查询是否存在 findMap 的结构数据
* @param arr getJsonV2 接口返回的权限列表
* @param findMap findItem[]
* @result boolean
*/
const isAccessInDataByMap = (arr, findMap) => {
let findList = arr // 重置查找范围
let i= 0 // 初始值
let tempArr = [] //
do {
tempArr = findList.filter(item => item[findMap[i].findkey] === findMap[i].findVal)
if(tempArr.length > 0){
findList = tempArr[0][findMap[i].childrenKey]
i++
}else{
return false
}
} while (i< findMap.length);
if(tempArr.length && i === findMap.length){
return true
}
}
ts版本
// tool-is-has-access-in-data-by-map.ts
// 声明接口
export interface findItem {
findKey: string
findVal: string
childrenKey: string
}
/**
* 查询是否存在 findMap 的结构数据
* @param arr getJsonV2 接口返回的权限列表
* @param findMap findItem[]
* @result boolean
*/
export const isAccessInDataByMap:(data:any, findMap:findItem[]) => boolean | undefined = (data:any, findMap:findItem[]) => {
let findList = data // 重置查找范围
let i= 0 // 记录下标
let tempArr = []
do {
tempArr = findList.filter((item: { [x: string]: string; }) => item[findMap[i].findKey] === findMap[i].findVal)
if(tempArr.length > 0){
findList = tempArr[0][findMap[i].childrenKey]
i++
}else{
return false
}
} while (i< findMap.length);
if(tempArr.length && i === findMap.length){
return true
}
};
后记
记录此方法的原因并非仅针对当前场景,更在于总结一种解决问题的思路。
通常的树状结构中,各层数据结构一致,仅最后一层无子元素,以此作为递归终止条件。而在本场景中,尽管各层数据结构相似,但用于核对的键值对却各不相同。因此,需要一把“尺子”来进行查找。
方法本身并不复杂,难点在于如何将其总结为通用解决方案,实现从0到1的突破,进而推广至从1到n的应用。
以上就是JS递归遍历查询是否有权限示例详解的详细内容,更多关于JS递归遍历查询权限的资料请关注本站其它相关文章!
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
