一般菜单组件接收到的菜单数据是有父组件传递下来的。如果对展开对菜单进行标记,那么菜单组件就会和父组件有交互。
本案里通过递归的方式直接在菜单组件进行数组push id 的方式进行数组对比进行判断菜单的展开状态。
菜单结构树
menu: [
{
name: "1",
id: "1",
children: [
{
name: "1-1",
id: "1-1",
children: [
],
},
{ name: "2", id: "2", children: [] },
{ name: "3", id: "3", children: [] },
],
},
{ name: "2", id: "2", children: [] },
{ name: "3", id: "3", children: [] },
]
菜单组件
import React, { useState } from "react";
import css from "./index.module.less";
export type MenuItem = {
id: string;
name: string;
children: Array<MenuItem>;
[propName: string]: any;
};
export type MenuProps = {
menu: Array<MenuItem>;
};
function checkArr(arr1: Array<string>, arr2: Array<string>) {
// 请确保菜单ID是唯一的,否则建议数组转字符串进行比较
const arr3: Array<string> = [];
if (arr2.length === 0) {
return false;
}
for (var i = 0; i < arr2.length; i++) {
if (arr1.indexOf(arr2[i]) > -1) {
arr3.push(arr2[i]);
}
}
if (arr3.length === arr1.length) {
return true;
} else {
return false;
}
}
function Menu(props: MenuProps) {
const { menu } = props;
const [thisPaths, setPaths] = useState([] as Array<string>);
function List(menu: Array<MenuItem>, paths: Array<string>) {
return menu.map((v) => {
return Item(v, paths);
});
}
function Item(item: MenuItem, paths: Array<string>) {
const newPaths: Array<string> = paths.concat(item.id);
const isOPen = checkArr(newPaths, thisPaths);
const hasChildren = Array.isArray(item.children) && item.children.length;
return (
<div
key={item.id}
className={`${css.item} ${isOPen ? css.open : ""} ${
hasChildren ? css["has-children"] : ""
}`}
>
<div
className={css.title}
onClick={() => {
setPaths(newPaths);
}}
>
{item.name}
</div>
<div className={css.children}>{List(item.children, newPaths)}</div>
</div>
);
}
return (
<div>
<div className={css.menu}>{List(menu, [])}</div>
</div>
);
}
export default Menu;
less
.menu {
padding: 24px;
font-size: 18px;
}
.item .item {
padding: 6px 0 6px 24px;
}
.title {
position: relative;
padding-left: 24px;
line-height: 40px;
color: #5a4d40;
cursor: pointer;
.active {
background-color: #ffdbb9;
}
&:hover {
background-color: #f9e4d1;
}
.has-children > &::before {
position: absolute;
top: 10px;
left: 7px;
content: "";
border-width: 10px;
border-style: solid;
border-color: transparent transparent transparent #ebb684;
transition: ease-out all 100ms;
}
}
.children {
display: none;
}
.open > .title {
// background-color: #ffdbb9;
&::before {
top: 15px;
left: 2px;
transform: rotate(90deg);
//border-color: #ebb684 transparent transparent transparent;
}
}
.open > .children {
display: block;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。