2019-09-23
描述
渲染一个包含多个可折叠内容组件的手风琴菜单。
- 定义一个
AccordionItem
组件,并将其传递给Accordion
。除了在props.children
中函数名称标识为AccordionItem
的节点外移除其余不必要的节点 - 每一个
AccordionItem
组件都渲染一个<button>
,通过props.handleClick
回调和传递到组件中的内容props.children
来更新Accordion
。他们的展现通过props.isCollapsed
及对应的style
来确定 - 在
Accordion
组件中,使用React.useState()
hook 来初始化状态变量bindIndex
的默认值为props.defaultIndex
- 在过滤出的节点中使用
Array.prototype.map
来渲染每一个可折叠的元素 - 定义
changeItem
方法,在点击AccordionItem
中的<button>
时将会被执行。changeItem
执行传递的回调函数onItemClick
并更新bindIndex
为被点击元素的index
属性值
实现
function AccordionItem(props) {
const style = {
collapsed: {
display: 'none'
},
expanded: {
display: 'block'
},
buttonStyle: {
display: 'block',
width: '100%'
}
};
return (
<div>
<button style={style.buttonStyle} onClick={() => props.handleClick()}>
{props.label}
</button>
<div
className="collapse-content"
style={props.isCollapsed ? style.collapsed : style.expanded}
aria-expanded={props.isCollapsed}
>
{props.children}
</div>
</div>
);
}
function Accordion(props) {
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
const changeItem = itemIndex => {
if (typeof props.onItemClick === 'function') props.onItemClick(itemIndex);
if (itemIndex !== bindIndex) setBindIndex(itemIndex);
};
const items = props.children.filter(item => item.type.name === 'AccordionItem');
return (
<div className="wrapper">
{items.map(({ props }) => (
<AccordionItem
isCollapsed={bindIndex !== props.index}
label={props.label}
handleClick={() => changeItem(props.index)}
children={props.children}
/>
))}
</div>
);
}
使用
ReactDOM.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>,
document.getElementById('root')
);