Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在React中创建动态嵌套手风琴_Javascript_Reactjs_Accordion - Fatal编程技术网

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

Javascript 如何在React中创建动态嵌套手风琴,javascript,reactjs,accordion,Javascript,Reactjs,Accordion,我怎样才能创作出这样的手风琴 -parent -subparent1 -subparent2 ... -subparentN - child 这是我的数据 //parents {id: 1, name: "", parent_id: null} {id: 2, name: "", parent_id: null } {id: 3, name: "", pa

我怎样才能创作出这样的手风琴

-parent
   -subparent1
      -subparent2
        ...
          -subparentN
             - child
这是我的数据

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

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


基本上,那些有parent_id:null的人是父母,当我点击他们时,我希望他们的潜在子女显示出来,如果他们有,现在这并不难,但我不明白的是如何显示子父母的子女,我认为您的数据结构有缺陷。除了父子关系之外,您还应该跟踪父子关系。现在,您将能够轻松地遍历数据并渲染子父级的子级

{id:1,父\u id:null,子项:[
{id:2,父\u id:1,子:[]},
{id:3,父\子id:1,子:[
{id:4,父\u id:3,子:[]}
]}
]}
如果需要使所有对象保持内联,可以按如下方式构造数据:

{id:1,父\u id:null,子:[2,3]}
{id:2,父\u id:1,子:[]},
{id:3,父\子id:1,子:[4]},
{id:4,父\u id:3,子:[]}

您可以循环查看所有项目的列表,并将每个子项目添加到其父项中。之后,您只需循环数组中的所有项并创建它们各自的html

const项=[
//父母
{id:1,名称:“1”,父\u id:null},
{id:2,名称:“2”,父\u id:null},
{id:3,名称:“3”,父\u id:null},
{id:4,名称:“4”,父\u id:null},
//孩子们
{id:5,名称:“5”,父id:1},
{id:6,名字:“6”,父id:1},
{id:7,姓名:“7”,家长id:5},
{id:8,姓名:“8”,家长id:5},
{id:9,姓名:“9”,家长id:6},
{id:10,姓名:“10”,家长id:6},
{id:11,姓名:“11”,家长id:6},
{id:12,姓名:“12”,家长id:6},
{id:13,姓名:“13”,家长id:6},
{id:14,姓名:“14”,家长id:6},
];
用于(项目的常数项){
//查找父对象
const parent=items.find(({id})=>id==item.parent\u id);
//如果找到父对象,则将该对象添加到其子数组中
如果(家长){
parent.children=parent.children?[…parent.children,item]:[item]
}
};
//仅在主数组中保留根元素(父元素)
const list=items.filter({parent\u id})=>!parent\u id);
//控制台日志(列表);
//显示树(vanillaJS,无反应)
用于(列表中的常量项){
//为每个项目创建一个新分支
const ul=创建分支(项目);
//将分支追加到文档中
文件.正文.附件(ul);
}
函数createBranch(项){
//为每个分支创建ul项目
const ul=document.createElement(“ul”);
//将当前项目作为li添加到分支
const li=document.createElement(“li”);
li.textContent=item.name;
ul.儿童(li);
//检查是否有孩子
if(项目.子项){
//为每个子级创建一个新分支
for(项的常量子项。子项){
const subUl=createBranch(子级);
//将子分支追加到当前分支
ul.儿童(subUl);
}
}
返回ul;
}
ul{
保证金:0;
左:2rem;

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

[
    {id: 1, name:"", children: [
      {id: 5, name: "", children: []},
      {id: 6, name: "", children: [
        {id: 7, name: "", children: []},
        {id: 8, name: "", children: []},
      ]},
    ]},
    {id: 2, name:"", 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;
}
一个完整的组件看起来如下所示:

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", children: [] },
              { 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;

你可以在这里找到一个工作的代码沙盒

创建子家长作为一个组件,并拥有自己的打开/关闭状态,然后点击传播,应该和你为家长所做的一样你是一个绝对的野兽,真正的天才,非常感谢你,你是一个救命恩人。我自己从来没有接近过这一点。顺便说一句,我有另一层的孩子,它的工作原理都一样,再次感谢!您好,回答得很好,如果我想显示所有元素,它会起作用,但我如何做手风琴之类的事情呢?我想按下父节点,让子节点折叠。我通常使用react引导包作为react引导包。然后,我将菜单包装在Nav()中,并将包含子菜单项的菜单项包装在UncontrolledDropdown元素()中。最后,对于项目,我使用NavItem元素。如果你想使用手风琴的方法,你可以用折叠()的方式将你的物品和子项包装起来。如果您觉得这很困难,或者不确定如何使用,请详细描述预期行为,我可以扩展我的答案以涵盖这一点。是的,请。我不知道如何使用您提供的returnMenuItem函数。非常感谢,所有这些嵌套和递归让我用一个示例组件更新了答案。您现在应该拥有根据需要构建组件所需的一切。干杯,随时乐意提供帮助。如果这是你想要的,那么你应该检查这是正确的答案。
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", children: [] },
              { 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;
.item {
  display: block;
}
.item > .children {
  padding: 0 0 0 40px;
}
.item > .toggler {
  display: inline-block;
}

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