Ant Design Timeline 交替模式(mode="alternate")完全指南:布局原理、源码解析与实战组合
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
Timeline(时间轴)是 Ant Design 中用于垂直展示按时间排列信息流的核心组件。本文围绕 components/timeline/demo/alternate.md 中演示的"交替展现"(Alternate)模式展开,深入讲解mode="alternate"的布局规则、底层实现原理,并结合仓库源码与测试用例,给出可直接复制运行的完整示例,以及它与dot、color、pending、reverse、label等属性的组合用法。读完本文,你将掌握 Timeline 交替布局的全部细节,并理解其 DOM 结构与 CSS 定位机制。
一、什么是交替模式:内容在时间轴两侧轮流出现
在默认(left)模式下,Timeline 的节点内容统一排在时间轴右侧;而alternate(交替)模式会让时间轴位于容器中央,节点内容依次在时间轴左右两侧轮流出现,形成类似"流水账 + 对照"的视觉结构。
官方 demo 对其的描述非常简洁(见 components/timeline/demo/alternate.md):
- zh-CN:内容在时间轴两侧轮流出现。
- en-US:Alternate timeline.
这种布局非常适合记录"来源与反馈成对出现"或"事件与结果左右对照"的场景,例如项目推进记录、会话往来、发布与修复记录等,左右交替能有效利用横向空间、提升长列表的可读性。
开箱即用的完整示例
下面是 demo 的完整实现(components/timeline/demo/alternate.tsx),它同时展示了交替布局、预设颜色与自定义时间轴点三种能力:
import React from 'react'; import { ClockCircleOutlined } from '@ant-design/icons'; import { Timeline } from 'antd'; const App: React.FC = () => ( <Timeline mode="alternate" items={[ { children: 'Create a services site 2015-09-01', }, { children: 'Solve initial network problems 2015-09-01', color: 'green', }, { dot: <ClockCircleOutlined style={{ fontSize: '16px' }} />, children: `Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.`, }, { color: 'red', children: 'Network problems being solved 2015-09-01', }, { children: 'Create a services site 2015-09-01', }, { dot: <ClockCircleOutlined style={{ fontSize: '16px' }} />, children: 'Technical testing 2015-09-01', }, ]} /> ); export default App;其中第二个节点使用了预设色green,第四个节点使用red,第三个与第六个节点通过dot替换成ClockCircleOutlined时钟图标。长文本(第三项)在交替布局中会被约束在单侧一半宽度内,自动换行而不会挤压时间轴。
二、交替布局规则:源码级解析
1. mode 属性的类型定义
在 components/timeline/Timeline.tsx 中,mode被定义为三种取值:
mode?: 'left' | 'alternate' | 'right';left(默认行为):时间轴在左侧,内容统一在右侧;alternate:时间轴居中,内容左右轮流;right:时间轴在右侧,内容统一在左侧。
2. 谁决定"这一条放左边还是右边"?
交替布局的核心逻辑位于 components/timeline/TimelineItemList.tsx 的getPositionCls函数:
const getPositionCls = (position: string, idx: number) => { if (mode === 'alternate') { if (position === 'right') return `${prefixCls}-item-right`; if (position === 'left') return `${prefixCls}-item-left`; return idx % 2 === 0 ? `${prefixCls}-item-left` : `${prefixCls}-item-right`; } if (mode === 'left') return `${prefixCls}-item-left`; if (mode === 'right') return `${prefixCls}-item-right`; if (position === 'right') return `${prefixCls}-item-right`; return ''; };可以总结出三条确定性规则:
- 交替兜底规则:不显式指定
position时,索引idx从 0 开始计数,偶数索引节点放在左侧(ant-timeline-item-left),奇数索引节点放在右侧(ant-timeline-item-right)。demo 中第 1、3、5 条在左,第 2、4、6 条在右,正是这一规则的体现。 - position 覆盖规则:单个节点的
position: 'left' | 'right'优先级最高,可手动把某一条钉在指定一侧,打破交替节奏。 - 其他模式:
left/right模式下所有节点统一归边,此时position仅对 alternate 之外的兜底逻辑产生部分影响。
此外,交替模式还会在根节点<ul>上追加ant-timeline-alternate类名(见 components/timeline/TimelineItemList.tsx),样式层据此启用居中定位。
3. 节点内部 DOM 结构
每个时间轴节点渲染为一个<li class="ant-timeline-item ...">,内部包含四个部分(见 components/timeline/TimelineItem.tsx):
<li {...restProps} className={itemClassName}> {label && <div className={`${prefixCls}-item-label`}>{label}</div>} <div className={`${prefixCls}-item-tail`} /> {/* 时间轴线 */} <div className={dotClassName} style={{ borderColor: customColor, color: customColor }}> {dot} </div> {/* 时间轴点 */} <div className={`${prefixCls}-item-content`}>{children}</div> {/* 内容 */} </li>ant-timeline-item-tail:竖直方向的轨迹线,由绝对定位的左边框实现;ant-timeline-item-head:圆形节点(10px,见下方 token 分析);ant-timeline-item-content:内容容器;- 当存在
label时,额外渲染ant-timeline-item-label。
4. 交替模式的样式定位原理
交替布局的 CSS 定义在 components/timeline/style/index.ts,关键点如下:
[`&${componentCls}-alternate, &${componentCls}-right, &${componentCls}-label`]: { [`${componentCls}-item`]: { '&-tail, &-head, &-head-custom': { insetInlineStart: '50%', // 时间轴、圆点、自定义点全部定位到容器 50% 处 }, '&-left': { [`${componentCls}-item-content`]: { insetInlineStart: `calc(50% - ${unit(token.marginXXS)})`, width: `calc(50% - ${unit(token.marginSM)})`, // 内容占左半侧 textAlign: 'start', }, }, '&-right': { [`${componentCls}-item-content`]: { width: `calc(50% - ${unit(token.marginSM)})`, // 内容占右半侧 margin: 0, textAlign: 'end', }, }, }, },要点:
- 交替模式下,
tail(轨迹)、head(圆点)、head-custom(自定义点)的insetInlineStart统一为50%,时间轴因此被钉在容器正中央; - 左侧节点(
item-left)内容宽度为50% - marginSM,靠右贴向时间轴,text-align: start; - 右侧节点(
item-right)内容同样占据右半侧宽度,text-align: end,内容靠左贴向时间轴; - 由于使用
insetInlineStart(逻辑属性)而非left,在 RTL(direction: rtl)环境下布局会自动镜像,无需额外处理。
三、进阶组合:交替模式 + 其他属性
1. 自定义时间轴点 dot
dot接受任意ReactNode。demo 中使用@ant-design/icons的ClockCircleOutlined替代默认圆点:
dot: <ClockCircleOutlined style={{ fontSize: '16px' }} />,从源码看,传入dot后节点会获得ant-timeline-item-head-custom类(components/timeline/TimelineItem.tsx),样式上取消圆角与边框、以transform: translate(-50%, -50%)精确居中(components/timeline/style/index.ts)。在交替模式下,自定义点同样被定位在 50% 处。
2. 节点颜色 color
color支持两类取值(components/timeline/TimelineItem.tsx):
- 预设色:
blue、red、green、gray(默认blue),分别映射主题 token 的colorPrimary、colorError、colorSuccess、colorTextDisabled,通过类名ant-timeline-item-head-blue等应用(见 components/timeline/style/index.ts); - 任意自定义色值(如
#ff0000、rgb(...)):源码通过正则/blue|red|green|gray/判断,非预设色时不会生成对应类名,而是以内联样式borderColor与color直接作用于圆点(components/timeline/TimelineItem.tsx)。测试 components/timeline/tests/index.test.tsx 对四种预设色与rgb(255, 0, 0)、rgba(...)、#ff0000等非预设色分别做了断言。
3. 与 pending(幽灵节点)组合
pending用于追加一个"进行中"的幽灵节点,可传入true或任意 ReactNode 作为其内容;配合pendingDot可替换默认的<LoadingOutlined />。实现上(components/timeline/TimelineItemList.tsx),pending为真值时会在 items 末尾追加一个pending: true的节点。交替模式下它与左右规则互不冲突,幽灵节点会按追加后的索引参与左右排布;测试用例has extra pending timeline item即验证了mode="alternate"与pending的共存(components/timeline/tests/index.test.tsx)。
4. 与 reverse(倒序)组合
reverse为true时整体反转渲染顺序(components/timeline/TimelineItemList.tsx),适用于"最新在前"的倒序时间流。注意:反转发生在位置类名计算之前,因此倒序后"左/右"归属会随索引重新计算,且ant-timeline-item-last标记也会随之调整——测试items is reversed when prop reverse is true验证了内容顺序变为['baz', 'bar', 'foo'](components/timeline/tests/index.test.tsx)。
5. 与 label(标签)的取舍
当任一节点设置label后,根节点会改用ant-timeline-label布局类,而不是ant-timeline-${mode}(见 components/timeline/TimelineItemList.tsx 中的hasLabelItem判断)。也就是说,label 布局与 alternate 交替布局在样式上是互斥的两套方案:需要时间标签(如日期列)时优先使用label方案;需要左右交替排版时则不设 label,使用mode="alternate"。
四、推荐用法与弃用提示
自5.2.0起,官方推荐使用items数组写法(见 components/timeline/index.zh-CN.md):
// >=5.2.0 可用,推荐的写法 ✅ const items = [{ children: 'sample', label: 'sample' }]; return <Timeline items={items} />; // <5.2.0 可用,>=5.2.0 时不推荐 🙅🏻♀️(将在 antd 6.0 移除) return ( <Timeline> <Timeline.Item>Sample</Timeline.Item> </Timeline> );源码中Timeline.Item仍保留以兼容旧代码,但在非生产环境下会通过devUseWarning输出弃用警告(components/timeline/Timeline.tsx);测试用例也断言了该警告文案Timeline.Item is deprecated. Please use items instead.(components/timeline/tests/index.test.tsx)。新项目应统一使用items写法,并借助 components/timeline/useItems.ts 完成新旧数据形态的归一化。
五、性能与样式可定制性
性能:
items写法直接以数组驱动渲染,无需逐个子组件嵌套,比旧的Timeline.Item组合式写法更利于 React 的 diff 与复用。设计 Token:Timeline 暴露了 5 个组件级 Token(见 components/timeline/style/index.ts 与 components/timeline/index.zh-CN.md):
tailColor:轨迹线颜色,默认取colorSplit;tailWidth:轨迹线宽度,默认lineWidthBold;dotBorderWidth:节点边框宽度,wireframe 模式下为lineWidthBold,否则为lineWidth * 3;dotBg:节点背景色,默认colorBgContainer;itemPaddingBottom:每个时间项的下间距,默认padding * 1.25。
交替模式下这些 Token 同样生效,例如调大
tailWidth会同时加粗中央轨迹线并影响圆点偏移的视觉平衡。
六、小结
mode="alternate"是 Timeline 三种布局(left/alternate/right)中最具表现力的一种:时间轴居中、内容左右轮流,且遵循"偶数索引靠左、奇数索引靠右、position优先覆盖"的确定性规则。配合dot、color、pending、reverse等属性,可以快速搭建出信息密度高、视觉层次清晰的对照式时间流。如需深入验证或二次开发,可继续阅读以下仓库源码:
- 演示源码:components/timeline/demo/alternate.tsx
- 组件入口与 props 定义:components/timeline/Timeline.tsx
- 交替布局核心逻辑:components/timeline/TimelineItemList.tsx
- 节点渲染:components/timeline/TimelineItem.tsx
- 样式与 Token:components/timeline/style/index.ts
- 测试用例:components/timeline/tests/index.test.tsx
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考