问题描述
我如何制作这样的手风琴
-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
上找到有效的代码沙箱。