概述
最近因项目需要对antd开发的项目实现菜单可筛选的功能,根据输入值,模糊查询所匹配的菜单并显示,因项目对国际化有要求,但项目中所有国际化资源文件均是以文件的形式提供,数据库仅存有国际化的key值,因此只能在前端对国际化后的菜单集合做的菜单做过滤,使用递归方式实现,需求描述如下。
1. 找出所有非叶子节点匹配的菜单项,将其子、子子节点直接显示
2. 找出所有叶子节点匹配项,将其父、祖父等祖籍节点直接显示
方式一,对传入后的值做筛选处理,修改getNavMenuItems及相关函数
//关键代码:
/**
* 获得菜单子节点
* @memberof SiderMenu
*/
getNavMenuItems = (menusData, parent) => {
if (!menusData || (Object.prototype.toString.call(menusData) != '[object Array]')) {
return [];
}
return menusData
.filter(item => item.name && !item.hideInMenu)
.map(item => {
// make dom
const str = "设备";
if(str == undefined || str.length < 1) { //查询为空时,全部显示
const ItemDom = this.getSubMenuOrItem2(item);
return this.checkPermissionItem(item.authority, ItemDom);
} else {
const parentList = this.checkParentMenu(item, str)
const list = parentList.flat(Infinity);
if(list != null && list.length > 0) { //祖籍节点匹配,该祖籍节点下子节点全部显示
const ItemDom = this.getSubMenuOrItem2(item);
return this.checkPermissionItem(item.authority, ItemDom);
} else { //子节点匹配,祖籍节点全部显示
const ItemDom = this.getSubMenuOrItem(item, str);
return this.checkPermissionItem(item.authority, ItemDom);
}
}
})
.filter(item => item);
};
/**
* 检测子菜单是否含有筛选关键字
*/
checkSubMenu = (children, str) => {
let list = [];
children.filter(item => item.name && !item.hideInMenu)
.map(item => {
if (item.children != undefined && item.children.length > 0 && !item.hideInMenu) {
list.push(this.checkSubMenu(item.children, str));
} else {
const name = formatMessage({ id: item.locale });
if (name.indexOf(str) != -1) {
list.push(true);
}
}
})
return list;
}
/**
* 菜单打平,将树形菜单列表化
*/
flatMapMenus = (menuData) => {
let list = [];
menuData.filter(item => item.name && !item.hideInMenu)
.map(item => {
list.push(item);
if (item.children != undefined && item.children.length > 0 && !item.hideInMenu) {
list.push(this.flatMapMenus(item.children));
}
})
return list;
}
/**
* 检测父菜单是否含有筛选关键字
*/
checkParentMenu = (item, str) => {
let list = [];
if(item != null && item.name && !item.hideInMenu) {
const name = formatMessage({ id: item.locale });
if (name.indexOf(str) != -1) {
list.push(true);
} else {
if(item.parent != null) {
const name = formatMessage({ id: item.parent.locale });
if (name.indexOf(str) != -1) {
list.push(true);
}
const { menuData } = this.props;
const menu = this.flatMapMenus(menuData).flat(Infinity).filter(menu => menu.id == item.parent.id);
list.push(this.checkParentMenu(menu.length > 0 ? menu[0] : null, str));
}
}
}
return list;
}
//菜单全部显示
getSubMenuOrItem2 = item => {
if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) {
const name = formatMessage({ id: item.locale });
return (
<SubMenu
title={
item.icon ? (
<span>
{getIcon(item.icon)}
<span>{name}</span>
</span>
) : (
name
)
}
key={item.path}
>
{this.getNavMenuItems(item.children)}
</SubMenu>
);
}
return <Menu.Item key={item.path}>{this.getMenuItemPath(item)}</Menu.Item>;
};
/**
* 检测子菜单匹配,显示祖籍菜单、匹配的子菜单
*/
getSubMenuOrItem = (item, str) => {
if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) {
const checkList = this.checkSubMenu(item.children, str);
const flatList = checkList.flat(Infinity);
const list = flatList.map(flag => flag == true ? true : false).filter(flag => flag);
const name = formatMessage({ id: item.locale });
if (list != undefined && list.length > 0) {
return (
<SubMenu
title={
item.icon ? (
<span>
{getIcon(item.icon)}
<span>{name}</span>
</span>
) : (
name
)
}
key={item.path}
>
{this.getNavMenuItems(item.children)}
</SubMenu>
);
} else {
}
}
if (formatMessage({ id: item.locale }).indexOf(str) != -1) {
return <Menu.Item key={item.path}>{this.getMenuItemPath(item)}</Menu.Item>;
}
};
方式二,对传入前的值做筛选(推荐):
1. 对传入的树形菜单集合做筛选,筛选出所有满足的节点,直接压入集合并返回,代码如下:
searchMenus = (menus, str) => {
if(str == undefined || str.length < 1){
return menus;
}
let list = [];
menus
.filter(item => item.name && !item.hideInMenu)
.map(item => {
if(formatMessage({ id: item.locale }).indexOf(str) != -1) {
list.push(item);
} else {
if(item.children && item.children.length) {
const child = this.searchMenus(item.children, str);
const node = {
...item,
children: child
};
if (child && child.length) {
list.push(node);
}
}
}
})
return list;
}
render方法渲染:
render() {
const { openKeys, theme, mode, location: { pathname,hash }, openUrls } = this.props;
let selectedKeys = this.getSelectedMenuKeys();
if (this.isEmpty(selectedKeys) && openKeys) {
selectedKeys = [hash===''?pathname:pathname+hash];
}
let props = {};
if (openKeys) {
props = {
openKeys: openUrls,
};
}
const { handleOpenChange, style, menuData } = this.props;
const list = this.searchMenus(menuData, "管理");
console.log(list);
return (
<Menu
key="Menu"
mode={mode}
theme={theme}
onOpenChange={handleOpenChange}
selectedKeys={selectedKeys}
style={style}
{...props}
>
{this.getNavMenuItems(list)} //方式二直接将传入的值menuData,改为筛选后的list
</Menu>
);
}
总结:两种方式都可以实现基于antd的菜单查询功能,推荐使用第二种方式,区别参考代码
最后
以上就是平淡小甜瓜为你收集整理的基于antd的Menu组件实现菜单查询的全部内容,希望文章能够帮你解决基于antd的Menu组件实现菜单查询所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复