如何在 React 中创建动态嵌套手风琴
How to create dynamic nested accordion in React
我如何制作这样的手风琴
-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的人都是parents,当我点击他们的时候我想让他们的潜力children显示出来,如果他们有的话,现在这个不是太难了,但我不明白的是如何显示子父母的 children
我认为你的数据结构有缺陷。除了 child 到 parent 的关系,您还应该跟踪 parent 到 child 的关系。现在您将能够轻松地遍历数据并呈现子 parent 的 children.
{id: 1, parent_id: null, children: [
{id: 2, parent_id: 1, children: []},
{id: 3, parent_id: 1, children: [
{id: 4, parent_id: 3, children: []}
]}
]}
如果您需要保持所有 objects 内联,您可以像这样构建数据:
{id: 1, parent_id: null, children: [2, 3]}
{id: 2, parent_id: 1, children: []},
{id: 3, parent_id: 1, children: [4]},
{id: 4, parent_id: 3, children: []}
您可以遍历所有项目的列表并将每个子项目添加到它们的父项。之后,您只需遍历数组中的所有项目并创建它们各自的 html.
const items = [
//parents
{id: 1, name: "1", parent_id: null},
{id: 2, name: "2", parent_id: null },
{id: 3, name: "3", parent_id: null },
{id: 4, name: "4", parent_id: null},
//children
{id: 5, name: "5", parent_id: 1},
{id: 6, name: "6", parent_id: 1},
{id: 7, name: "7", parent_id: 5},
{id: 8, name: "8", parent_id: 5},
{id: 9, name: "9", parent_id: 6},
{id: 10, name: "10", parent_id: 6},
{id: 11, name: "11", parent_id: 6},
{id: 12, name: "12", parent_id: 6},
{id: 13,name: "13", parent_id: 6},
{id: 14, name: "14", parent_id: 6},
];
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: 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;
}
您将通过遍历项目来调用此函数:
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", 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;
并且至少 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
我如何制作这样的手风琴
-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的人都是parents,当我点击他们的时候我想让他们的潜力children显示出来,如果他们有的话,现在这个不是太难了,但我不明白的是如何显示子父母的 children
我认为你的数据结构有缺陷。除了 child 到 parent 的关系,您还应该跟踪 parent 到 child 的关系。现在您将能够轻松地遍历数据并呈现子 parent 的 children.
{id: 1, parent_id: null, children: [
{id: 2, parent_id: 1, children: []},
{id: 3, parent_id: 1, children: [
{id: 4, parent_id: 3, children: []}
]}
]}
如果您需要保持所有 objects 内联,您可以像这样构建数据:
{id: 1, parent_id: null, children: [2, 3]}
{id: 2, parent_id: 1, children: []},
{id: 3, parent_id: 1, children: [4]},
{id: 4, parent_id: 3, children: []}
您可以遍历所有项目的列表并将每个子项目添加到它们的父项。之后,您只需遍历数组中的所有项目并创建它们各自的 html.
const items = [
//parents
{id: 1, name: "1", parent_id: null},
{id: 2, name: "2", parent_id: null },
{id: 3, name: "3", parent_id: null },
{id: 4, name: "4", parent_id: null},
//children
{id: 5, name: "5", parent_id: 1},
{id: 6, name: "6", parent_id: 1},
{id: 7, name: "7", parent_id: 5},
{id: 8, name: "8", parent_id: 5},
{id: 9, name: "9", parent_id: 6},
{id: 10, name: "10", parent_id: 6},
{id: 11, name: "11", parent_id: 6},
{id: 12, name: "12", parent_id: 6},
{id: 13,name: "13", parent_id: 6},
{id: 14, name: "14", parent_id: 6},
];
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: 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;
}
您将通过遍历项目来调用此函数:
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", 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;
并且至少 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