可折叠的手风琴
渲染一个带有多个可折叠内容元素的手风琴菜单。
- 定义一个
AccordionItem
组件,它渲染一个<button>
。该按钮通过handleClick
回调函数更新组件并通知其父组件。 - 在
AccordionItem
中使用isCollapsed
属性来确定其外观并设置其className
。 - 定义一个
Accordion
组件。使用useState()
钩子将bindIndex
状态变量的初始值设置为defaultIndex
。 - 通过识别函数的名称,过滤
children
来删除除AccordionItem
之外的不必要的节点。 - 对收集到的节点使用
Array.prototype.map()
来渲染各个可折叠元素。 - 定义
changeItem
,当点击AccordionItem
的<button>
时将执行该函数。 changeItem
执行传递的回调函数onItemClick
,并根据点击的元素更新bindIndex
。
.accordion-item.collapsed {
display: none;
}
.accordion-item.expanded {
display: block;
}
.accordion-button {
display: block;
width: 100%;
}
const AccordionItem = ({ label, isCollapsed, handleClick, children }) => {
return (
<>
<button className="accordion-button" onClick={handleClick}>
{label}
</button>
<div
className={`accordion-item ${isCollapsed ? 'collapsed' : 'expanded'}`}
aria-expanded={isCollapsed}
>
{children}
</div>
</>
);
};
const Accordion = ({ defaultIndex, onItemClick, children }) => {
const [bindIndex, setBindIndex] = React.useState(defaultIndex);
const changeItem = itemIndex => {
if (typeof onItemClick === 'function') onItemClick(itemIndex);
if (itemIndex !== bindIndex) setBindIndex(itemIndex);
};
const items = children.filter(item => item.type.name === 'AccordionItem');
return (
<>
{items.map(({ props }) => (
<AccordionItem
isCollapsed={bindIndex !== props.index}
label={props.label}
handleClick={() => changeItem(props.index)}
children={props.children}
/>
))}
</>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<Accordion defaultIndex="1" onItemClick={console.log}>
<AccordionItem label="A" index="1">
Lorem ipsum
</AccordionItem>
<AccordionItem label="B" index="2">
Dolor sit amet
</AccordionItem>
</Accordion>
);
ReactDOM.createRoot(document.getElementById('root')).render(