不修改樹結構菜單屬性對菜單進行無限展開

通常菜單組件接收到的菜單數據是有父組件傳遞下來的。若是對展開對菜單進行標記,那麼菜單組件就會和父組件有交互。css

本案裏經過遞歸的方式直接在菜單組件進行數組push id 的方式進行數組對比進行判斷菜單的展開狀態。react

菜單結構樹數組

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: [] },
      ]

菜單組件less

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;

lessthis

.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;
}

樹行菜單展開效果圖

相關文章
相關標籤/搜索