가이가 문제에 직면하고 있습니다. 2 차원 데이터가 있습니다. 데이터에는 링크가 포함 된 중첩 구조가 있습니다.
const data = [
// First Div Panel
[
{
id: 1,
url: "/services",
title: "Services"
},
{
id: 2,
title: "Products",
children: [
{
id: 3,
url: "/themes-templates",
title: "Themes & Templates"
},
{
id: 4,
url: "/open-source",
title: "Open Source"
},
{
id: 5,
url: "/solutions",
title: "Solutions"
}
]
},
{
id: 6,
url: "/work",
title: "Work",
children: [
{
id: 7,
url: "/methodology",
title: "Methodology",
children: [
{
id: 8,
url: "/agile",
title: "Agile",
children: [
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
}
]
}
]
},
{
id: 10,
url: "/contact-us",
title: "Contact Us"
}
],
// Second Div Panel which contains children of second list item
[
{
id: 3,
url: "/themes-templates",
title: "Themes & Templates"
},
{
id: 4,
url: "/open-source",
title: "Open Source"
},
{
id: 5,
url: "/solutions",
title: "Solutions"
}
],
// Third Div Panel which contains children of third list item
[
{
id: 7,
url: "/methodology",
title: "Methodology",
children: [
{
id: 8,
url: "/agile",
title: "Agile",
children: [
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
}
]
}
],
// Fourth Div Panel contains the children of the 3rd sub list item
[
{
id: 8,
url: "/agile",
title: "Agile",
children: [
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
}
],
// Fourth Div Panel contains the children of the 3rd sub sub list item
[
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
];
내 임무는 그 2 차원 데이터를 활용 react
하고 푸시 패널과 같은 구조 의 모바일 메뉴를 만드는 것입니다.
그럼에도 불구하고, 나는 이런 식으로 만들려고합니다. 내가 한 일은 모든 하위 배열을 별도의 패널로 취급하는 것 div
입니다. 먼저, 서브 어레이 항목은 기본적으로 보이는 루트 패널에서 고려됩니다. 항목에 children
속성 이있는 경우 next
해당 목록 항목에 동적 버튼이 생성됨을 의미합니다. 이 버튼을 클릭 is-visible
하면 패널에 클래스 가 추가 됩니다. 그러나 문제는 버튼 클릭과 관련된 패널을 어떻게 추적 할 것인가입니다. 내가 가진 상태를 사용하려고 activeId
하고 prevId
하지만 내 색인이 제대로 작동하지 않는 및 올바른 패널을 열 수 없습니다. Chrome 관리자 패널에서 내 솔루션을 검사 할 수 있습니다. 내가 뭘 잘못하고 있는지 말해줘서 고마워?
암호:
// Get a hook function
const {useState} = React;
//#region Data
const data = [
// First Div Panel
[
{
id: 1,
url: "/services",
title: "Services"
},
{
id: 2,
title: "Products",
children: [
{
id: 3,
url: "/themes-templates",
title: "Themes & Templates"
},
{
id: 4,
url: "/open-source",
title: "Open Source"
},
{
id: 5,
url: "/solutions",
title: "Solutions"
}
]
},
{
id: 6,
url: "/work",
title: "Work",
children: [
{
id: 7,
url: "/methodology",
title: "Methodology",
children: [
{
id: 8,
url: "/agile",
title: "Agile",
children: [
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
}
]
}
]
},
{
id: 10,
url: "/contact-us",
title: "Contact Us"
}
],
// Second Div Panel
[
{
id: 3,
url: "/themes-templates",
title: "Themes & Templates"
},
{
id: 4,
url: "/open-source",
title: "Open Source"
},
{
id: 5,
url: "/solutions",
title: "Solutions"
}
],
// Third Div Panel
[
{
id: 7,
url: "/methodology",
title: "Methodology",
children: [
{
id: 8,
url: "/agile",
title: "Agile",
children: [
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
}
]
}
],
// Fourth Div Panel
[
{
id: 8,
url: "/agile",
title: "Agile",
children: [
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
}
],
// Fifth Div Panel
[
{
id: 9,
url: "/scrum",
title: "Scrum"
}
]
];
//#endregion Data
//#region Component
const PanelMenu = props => {
const { title } = props;
const [items, setItems] = useState(data);
// Title Header of the Panel
const [headerTitle, setHeaderTitle] = useState(title ? title : "");
// Previous Title Header of the Panel
const [prevHeaderTitle, setPrevHeaderTitle] = useState(title ? title : "");
// ActiveIndex => 0 means by default master-panel is active
const [activeId, setActiveId] = useState(0);
// PreviousIndex
const [prevId, setPrevId] = useState(0);
const handlePanelBtn = (newTitle, index, prevIndex) => {
// Title Checking
const titleProp = title ? title : "";
const prevTitle = index === 0 ? titleProp : headerTitle;
// SetStates
setPrevHeaderTitle(prevTitle);
setHeaderTitle(newTitle);
setActiveId(index);
setPrevId(prevIndex);
};
const panelRenderer = () => {
const panelsJSX = [];
for (let i = 0; i < items.length; i++) {
let childItemIndex = i;
const panels = (
<div
key={i}
id={i === 0 ? "p__master" : `p__student-${i}`}
className={
childItemIndex === activeId
? "p__panel is-visible"
: "p__panel is-hide"
}
>
<ul>
{items[i].map((item, index) => {
// It means it have children
if (item.children && item.children.length > 0) {
childItemIndex++;
return (
<li key={item.id} className="p-next">
{item.url ? (
<a href={item.url} className="p-link">
{item.title}
</a>
) : (
<div className="p-link">{item.title}</div>
)}
<button
type="button"
className="p-next__btn"
data-id={`#p__student-${childItemIndex}`}
onClick={() => handlePanelBtn(item.title, index, prevId)}
>
<span>></span>
</button>
</li>
);
} else {
return (
<li key={item.id}>
<a href={item.url} className="p-link">
{item.title}
</a>
</li>
);
}
})}
</ul>
</div>
);
panelsJSX.push(panels);
}
return panelsJSX;
};
const renderer = () => {
if (items && items.length > 0) {
return (
<div className="p">
<div className="p__wrap">
{/* Panel Actions => Header */}
<div className="p__actions">
{/* Previous Button */}
{activeId !== 0 && (
<button
type="button"
className="p-action__btn left"
onClick={() =>
handlePanelBtn(prevHeaderTitle, prevId, prevId)
}
>
<span><</span>
</button>
)}
{/* Title */}
{headerTitle && (
<div className="p-action__title">{headerTitle}</div>
)}
{/* Close Button */}
<button type="button" className="p-action__btn right">
<span>×</span>
</button>
</div>
{/* Panel children Wrapper */}
<div className="p__children">{panelRenderer()}</div>
</div>
</div>
);
}
};
return <React.Fragment>{renderer()}</React.Fragment>;
};
//#endregion Component
// Render it
ReactDOM.render(
<PanelMenu title="Menu" />,
document.getElementById("root")
)
<style>
*,:before,:after {
box-sizing: border-box;
}
.p__wrap {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 320px;
background-color: #fff;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
z-index: 1;
color: #333;
overflow-x: hidden;
}
.p__actions {
position: relative;
padding: 14px;
min-height: 54px;
border-bottom: 1px solid #dcdcdc;
}
.p-action__title {
text-align: center;
color: #333;
text-transform: uppercase;
font-weight: 700;
}
.p-action__btn {
position: absolute;
width: 54px;
height: 54px;
top: 0;
right: 0;
font-size: 16px;
color: #333;
border: none;
cursor: pointer;
}
.left {
left: 0;
}
.right {
right: 0;
}
.p__children {
position: relative;
background-color: #fff;
overflow: hidden;
height: calc(100% - 54px);
}
.p__panel {
overflow-x: hidden;
overflow-y: auto;
position: absolute;
transform: translateX(100%);
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 0;
transition: transform 0.2s ease 0s;
}
.p__panel.is-visible {
transform: translateX(0);
z-index: 1;
}
.p__panel.is-hide {
opacity: 0;
visibility: hidden;
}
.p__panel > ul {
margin: 0;
padding: 0;
}
.p__panel > ul > li {
list-style: none;
border-bottom: 1px solid #dcdcdc;
}
.p__panel > ul > li > .p-link {
color: #333;
display: block;
line-height: 22px;
font-size: 14px;
padding: 14px 24px;
background-color: transparent;
cursor: pointer;
}
.p__panel > ul > li > .p-link:hover {
background-color: #dcdcdc;
}
.p-next {
position: relative;
}
.p-next__btn {
position: absolute;
padding: 14px 16px;
font-size: 16px;
line-height: 22px;
top: 0;
right: 0;
background-color: rgb(240,240,240);
color: #333;
border: none;
border-left: 1px solid #dcdcdc;
cursor: pointer;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>