React火车行程组件:用CSS Flex/Grid实现节点垂直线连接
嘿,我帮你梳理下实现火车行程节点连线的思路,完全用Flex布局就能搞定,而且代码结构清晰!
实现思路与代码示例
1. 整体布局结构
首先,整个行程列表是垂直的Flex容器,每个单段行程项又是横向的Flex容器,拆成三个核心区域:时间区、节点连线区、站点信息区。这种布局能保证三个部分自动对齐,还能适配不同屏幕宽度。
2. 核心:节点与垂直线的实现
节点连线的视觉效果是关键,我推荐用「主垂直线+圆形节点覆盖」的方案,简单又可靠:
- 给节点容器设置
position: relative,内部加一条绝对定位的垂直线,贯穿整个容器高度; - 每个圆形节点用和页面背景一致的底色,边框颜色和垂直线统一,这样圆形会覆盖住下方的线,自然形成“节点间有连线”的效果;
- 给当前行程的节点加特殊样式(比如填充色),能快速突出显示。
3. 子组件拆分与整合
把时间、节点、站点信息拆成独立的React组件,方便后续复用和维护,父组件只负责组合布局逻辑。
React组件示例
import React from 'react'; import './TripItinerary.css'; // 时间子组件 const TimeComponent = ({ time }) => ( <div className="trip-time"> <span>{time}</span> </div> ); // 节点子组件 const NodesComponent = ({ nodes, currentIndex }) => ( <div className="trip-nodes"> {/* 贯穿整个节点区的垂直线 */} <div className="nodes-vertical-line"></div> {nodes.map((node, index) => ( <div key={index} className={`node ${index === currentIndex ? 'node-active' : ''}`} > <div className="node-circle"></div> </div> ))} </div> ); // 站点信息子组件 const InfoComponent = ({ station, status }) => ( <div className="trip-info"> <h3>{station}</h3> <p className="status">{status}</p> </div> ); // 父组件:组合所有子组件 const TripItinerary = ({ trips }) => ( <div className="trip-container"> {trips.map((trip, index) => ( <div key={index} className="trip-item"> <TimeComponent time={trip.time} /> <NodesComponent nodes={trip.nodes} currentIndex={trip.currentIndex} /> <InfoComponent station={trip.station} status={trip.status} /> </div> ))} </div> ); export default TripItinerary;
CSS样式(TripItinerary.css)
/* 整体行程容器:垂直排列所有行程项 */ .trip-container { display: flex; flex-direction: column; gap: 2rem; padding: 1rem; max-width: 800px; margin: 0 auto; } /* 单个行程项:横向排列三个区域 */ .trip-item { display: flex; align-items: flex-start; gap: 1.5rem; } /* 时间区:固定宽度,避免挤压 */ .trip-time { flex-shrink: 0; width: 60px; text-align: center; font-weight: bold; color: #333; } /* 节点连线区:垂直排列所有节点 */ .trip-nodes { position: relative; display: flex; flex-direction: column; gap: 1.5rem; align-items: center; } /* 贯穿的垂直线:绝对定位在节点区中间 */ .nodes-vertical-line { position: absolute; top: 0; bottom: 0; left: 12px; /* 对应圆形直径24px,保证线在圆心位置 */ width: 2px; background-color: #ccc; } /* 单个节点:设置层级确保圆形在垂直线上方 */ .node { position: relative; z-index: 1; } .node-circle { width: 24px; height: 24px; border-radius: 50%; border: 2px solid #ccc; background-color: white; /* 用底色覆盖垂直线 */ } /* 活跃节点样式:突出当前行程 */ .node-active .node-circle { background-color: #007bff; border-color: #007bff; } /* 站点信息区:占据剩余空间 */ .trip-info { flex: 1; } .trip-info h3 { margin: 0 0 0.5rem 0; color: #333; } .status { margin: 0; color: #666; font-size: 0.9rem; }
额外优化提示
- 响应式适配:可以给
.trip-item加媒体查询,小屏幕下改成垂直布局,提升移动端体验; - 自定义样式:根据需求调整节点大小、连线颜色、活跃节点样式,轻松匹配产品设计;
- 扩展功能:节点里可以添加图标(比如火车、换乘标识),信息区可以增加延误时间、站台号等实时数据。
内容的提问来源于stack exchange,提问作者Rafael Rocha
相关产品推荐
相关产品推荐

