微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在React中创建动态嵌套手风琴

如何解决如何在React中创建动态嵌套手风琴

我如何制作这样的手风琴

-parent
   -subparent1
      -subparent2
        ...
          -subparentN
             - child

这是我的数据。

//parents
{id: 1,name: "",parent_id: null}
{id: 2,parent_id: null }
{id: 3,parent_id: null }
{id: 4,parent_id: null}

//children
{id: 5,parent_id: 1}
{id: 6,parent_id: 1}
{id: 7,parent_id: 5}
{id: 8,parent_id: 5}
{id: 9,parent_id: 6}
{id: 10,parent_id: 6}
{id: 11,parent_id: 6}
{id: 12,parent_id: 6}
{id: 13,parent_id: 6}
{id: 14,parent_id: 6}

基本上具有parent_id:null的是父母,当我单击它们时,我希望显示潜在的孩子(如果有的话),这并不难,但是我不知道如何显示下级父母的孩子

解决方法

我认为您的数据结构存在缺陷。除了孩子与父母的关系之外,您还应该跟踪父母与孩子的关系。现在,您将可以轻松地遍历数据并呈现子父级的子级。

{id: 1,parent_id: null,children: [
  {id: 2,parent_id: 1,children: []},{id: 3,children: [
    {id: 4,parent_id: 3,children: []}
  ]}
]}

如果需要使所有对象保持内联,则可以像以下那样构造数据:

{id: 1,children: [2,3]}
{id: 2,children: [4]},{id: 4,children: []}
,

您可以遍历所有项的列表,并将每个子项添加到其父项。然后,您只需要遍历数组中的所有项目并创建它们各自的html。

const items = [
  //parents
  {id: 1,name: "1",parent_id: null},{id: 2,name: "2",parent_id: null },name: "3",name: "4",//children
  {id: 5,name: "5",parent_id: 1},{id: 6,name: "6",{id: 7,name: "7",parent_id: 5},{id: 8,name: "8",{id: 9,name: "9",parent_id: 6},{id: 10,name: "10",{id: 11,name: "11",{id: 12,name: "12",{id: 13,name: "13",{id: 14,name: "14",];

for(const item of items) {
  // Find the parent object
  const parent = items.find(({ id }) => id === item.parent_id);
  // If the parent is found add the object to its children array
  if(parent) {
    parent.children = parent.children ? [...parent.children,item] : [item]
  }
};

// Only keep root elements (parents) in the main array
const list = items.filter(({ parent_id }) => !parent_id);

// console.log(list);

// Show tree (vanillaJS,no REACT)
for(const item of list) {
  // Create a new branch for each item
  const ul = createBranch(item);
  // Append branch to the document
  document.body.appendChild(ul);
}

function createBranch(item) {
  // Create ul item for each branch
  const ul = document.createElement("ul");
  // Add current item as li to the branch
  const li = document.createElement("li");
  li.textContent = item.name;
  ul.appendChild(li);

  // Check if there are children
  if(item.children) {
    // Create a new branch for each child
    for(const child of item.children) {
      const subUl = createBranch(child);
      // Append child branch to current branch
      ul.appendChild(subUl);
    }
  }
  
  return ul;
}
ul {
  margin: 0;
  padding-left: 2rem;
}

,

我认为您的数据结构应该是一个嵌套对象,类似于您看到菜单工作的方式,即

[
    {id: 1,name:"",children: [
      {id: 5,name: "",children: [
        {id: 7,]},children:[]}
]

然后,您将需要一个函数来输出每个项目:

const returnMenuItem = (item,i) =>{
  let menuItem;

  if (item.children.length===0) {
    menuItem = <div key={i}>{item.label}</div>;
  }
  else {
    let menuItemChildren = item.children.map((item,i)=>{
      let menuItem = returnMenuItem(item,i);
      return menuItem;
    });
    menuItem = <div key={i}>
      <div>{item.label}</div>
      <div>
        {menuItemChildren}
      </div>
    </div>;
  }
  return menuItem;
}

您将通过遍历项目来调用此功能:

let menuItems = data.map((item,i)=>{
    let menuItem = returnMenuItem(item,i);
    return menuItem;
});

一个完整的组件如下所示:

import React,{ useState,useEffect } from "react";
import { UncontrolledCollapse } from "reactstrap";

const Menu = (props) => {

  const [loading,setLoading] = useState(true);
  const [items,setItems] = useState([]);

  useEffect(() => {
    const menuData = [
      {
        id: 1,name: "test 1",children: [
          { id: 5,name: "test 5",children: [] },{
            id: 6,name: "test 6",children: [
              { id: 7,name: "test 7",{ id: 8,name: "test 8",children: [] }
            ]
          }
        ]
      },{ id: 2,name: "test 2",children: [] }
    ];
    const returnMenuItem = (item,i) => {
      let menuItem;

      if (item.children.length === 0) {
        menuItem = (
          <div className="item" key={i}>
            {item.name}
          </div>
        );
      } else {
        let menuItemChildren = item.children.map((item,i) => {
          let menuItem = returnMenuItem(item,i);
          return menuItem;
        });
        menuItem = (
          <div key={i} className="item">
            <div className="toggler" id={`toggle-menu-item-${item.id}`}>
              {item.name}
            </div>
            <UncontrolledCollapse
              className="children"
              toggler={`#toggle-menu-item-${item.id}`}
            >
              {menuItemChildren}
            </UncontrolledCollapse>
          </div>
        );
      }
      return menuItem;
    };

    const load = async () => {
      setLoading(false);
      let menuItems = menuData.map((item,i) => {
        let menuItem = returnMenuItem(item,i);
        return menuItem;
      });
      setItems(menuItems);
    };
    if (loading) {
      load();
    }
  },[loading]);

  return <div className="items">{items}</div>;
};
export default Menu;

以及最低CSS:

.item {
  display: block;
}
.item > .children {
  padding: 0 0 0 40px;
}
.item > .toggler {
  display: inline-block;
}

.item::before {
  content: "-";
  padding: 0 5px 0 0;
}

您可以在sandbox

上找到有效的代码沙箱。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。