如何用React按邮轮公司展示邮轮列表并实现展开收起功能
解决邮轮公司分组与展开收起列表的方案
嘿,我来帮你搞定这个分组展示邮轮的问题!要实现按邮轮公司分组+展开收起的功能,咱们可以分成两步走:先把邮轮数据按公司分组,再集成Accordion组件实现展开收起。下面是具体的实现方案:
1. 先处理数据分组
首先需要把你的shipList数组按照cruise_line字段进行分组。咱们可以写一个工具函数,用数组的reduce方法来完成这个逻辑:
const groupShipsByCruiseLine = (ships) => { return ships.reduce((groups, ship) => { const cruiseLine = ship.cruise_line || '未归属公司'; // 处理没有cruise_line的异常情况 if (!groups[cruiseLine]) { groups[cruiseLine] = []; } groups[cruiseLine].push(ship); return groups; }, {}); };
这个函数会把原始的邮轮数组转换成一个对象,键是邮轮公司名称,值是对应公司的邮轮数组,方便后续按组渲染。
2. 集成Accordion组件实现展开收起
这里我用React Bootstrap的Accordion组件来实现(如果还没安装依赖,先执行npm install react-bootstrap bootstrap),当然你也可以用其他UI库的Accordion,或者自己实现一个简易版。
下面是修改后的完整ListofShips组件代码:
import React from 'react'; import { Link } from 'react-router-dom'; import { Accordion, Card, Button } from 'react-bootstrap'; // 导入Accordion相关组件 import { getAllShips } from '../api/api'; class ListofShips extends React.Component { constructor(props) { super(props); this.state = { shipList: [], expandedCruiseLine: null, // 控制当前展开的面板,默认全部收起 }; this.setUpShips = this.setUpShips.bind(this); this.toggleAccordion = this.toggleAccordion.bind(this); } componentDidMount() { this.setUpShips(); } setUpShips() { getAllShips() .then(res => { this.setState({ shipList: res }); }); } // 切换Accordion的展开/收起状态 toggleAccordion(cruiseLine) { this.setState(prevState => ({ expandedCruiseLine: prevState.expandedCruiseLine === cruiseLine ? null : cruiseLine, })); } // 分组数据的工具函数 groupShipsByCruiseLine(ships) { return ships.reduce((groups, ship) => { const cruiseLine = ship.cruise_line || '未归属公司'; if (!groups[cruiseLine]) { groups[cruiseLine] = []; } groups[cruiseLine].push(ship); return groups; }, {}); } render() { const groupedShips = this.groupShipsByCruiseLine(this.state.shipList); // 把分组后的对象转换成数组,方便遍历渲染 const cruiseLines = Object.entries(groupedShips); return ( <Accordion> {cruiseLines.map(([cruiseLine, ships]) => ( <Card key={cruiseLine}> <Card.Header> <Button variant="link" onClick={() => this.toggleAccordion(cruiseLine)} className="w-100 text-left" > {cruiseLine} ({ships.length}艘邮轮) </Button> </Card.Header> {this.state.expandedCruiseLine === cruiseLine && ( <Accordion.Collapse eventKey={cruiseLine}> <Card.Body> <ul className="shipsList"> {ships.map(ship => ( <li key={ship.id}> <Link to={`/ship/${ship.id}`}>{ship.ship_name}</Link> </li> ))} </ul> </Card.Body> </Accordion.Collapse> )} </Card> ))} </Accordion> ); } } export default ListofShips;
关键逻辑说明
- 数据分组:通过
groupShipsByCruiseLine把原始数据整理成按公司分组的结构,让后续渲染逻辑更清晰。 - 展开收起控制:用
expandedCruiseLine状态记录当前展开的公司面板,点击按钮时切换状态,控制对应面板内容的显示/隐藏。 - UI渲染:遍历每个邮轮公司生成对应的Accordion面板,面板展开后展示该公司下的所有邮轮列表,同时在标题上标注邮轮数量提升用户体验。
如果你不想依赖第三方UI库,也可以自己写一个简易版Accordion:核心逻辑就是通过状态控制面板内容的display属性(block/none),同样能实现展开收起效果。
内容的提问来源于stack exchange,提问作者Rob Wilkinson
相关产品推荐
相关产品推荐

