Ant Design Descriptions 组件实战指南:用 items 声明式 API 构建企业级详情页只读信息展示
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
Descriptions 是 Ant Design 中用于「成组展示多条只读字段」的经典信息展示组件,最常见的落地场景是订单详情、用户信息、商品规格等详情页(Details Page)。本文以官方文档 components/descriptions/index.en-US.md 为核心骨架,结合仓库内组件源码与真实 Demo,系统讲解 Descriptions 的两种数据声明方式、全部 API 参数、响应式列数/跨度控制、样式定制优先级以及 Design Token 定制方法,读完即可在项目中直接落地一套适配多端屏幕的详情信息面板。
何时使用 Descriptions
官方文档给出的定位非常明确:Commonly displayed on the details page(通常展示在详情页)。当页面需要将一组只读字段(如用户名、电话、地址)以「标签 + 内容」的表格形式整齐排列时,Descriptions 是比手工拼 table 更语义化、更省心的选择。它与 Form 的核心区别在于:Descriptions 不承载交互输入,纯粹用于信息陈列。
两种数据声明方式:items数组与 JSX 子组件
自 5.8.0 起,Descriptions 推荐使用items数组声明数据,而基于<Descriptions.Item>子组件的旧写法在 5.8.0 之后被标记为 deprecated。官方文档给出了两种写法的对照:
// 推荐写法:works when >= 5.8.0 ✅ const items: DescriptionsProps['items'] = [ { key: '1', label: 'UserName', children: <p>Zhou Maomao</p> }, { key: '2', label: 'Telephone', children: <p>1810000000</p> }, { key: '3', label: 'Live', children: <p>Hangzhou, Zhejiang</p> }, { key: '4', label: 'Remark', children: <p>empty</p> }, { key: '5', label: 'Address', children: <p>No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China</p>, }, ]; <Descriptions title="User Info" items={items} />; // 旧写法:works when <5.8.0,>=5.8.0 起不推荐 🙅🏻♀️ <Descriptions title="User Info"> <Descriptions.Item label="UserName">Zhou Maomao</Descriptions.Item> <Descriptions.Item label="Telephone">1810000000</Descriptions.Item> <Descriptions.Item label="Live">Hangzhou, Zhejiang</Descriptions.Item> <Descriptions.Item label="Remark">empty</Descriptions.Item> <Descriptions.Item label="Address"> No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China </Descriptions.Item> </Descriptions>;从源码看,两种写法最终会汇合到同一条数据管线:useItems钩子(components/descriptions/hooks/useItems.ts)中优先消费items属性,若未传入则调用transChildren2Items把<Descriptions.Item>子节点的props与key转换为等价的对象数组:
const mergedItems = React.useMemo<DescriptionsItemType[]>( () => // Take `items` first or convert `children` into items items || transChildren2Items(children), [items, children], );因此两者渲染结果完全一致,items只是更利于与后端数据、状态管理直接对接。
Descriptions API 参数详解
官方文档的完整参数表如下(均可在源码 components/descriptions/index.tsx#L31-L51 的DescriptionsProps中找到一一对应的类型定义):
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| bordered | 是否显示边框 | boolean | false | - |
| colon | 修改 Descriptions.Item 默认的colon属性值,控制标签后冒号是否显示 | boolean | true | - |
| column | 一行内DescriptionItems的数量,可为数字或对象如{ xs: 8, sm: 16, md: 24 } | number | Record<Breakpoint, number> | 3 | - |
| contentStyle | 自定义内容样式 | CSSProperties | - | 4.10.0 |
| extra | 描述列表的操作区域,位于右上角 | ReactNode | - | 4.5.0 |
| items | 描述列表项的内容 | DescriptionsItem[] | - | 5.8.0 |
| labelStyle | 自定义标签样式 | CSSProperties | - | 4.10.0 |
| layout | 定义描述布局 | horizontal|vertical | horizontal | - |
| size | 设置列表尺寸,可为middle、small或不填 | default|middle|small | - | - |
| title | 描述列表的标题,位于顶部 | ReactNode | - | - |
除表格所列属性外,DescriptionsProps还声明了prefixCls、className、rootClassName、style、id等通用属性,并支持透传 ConfigProvider 提供的direction(RTL 场景下会自动追加-rtl类名,见 index.tsx#L113)。
值得注意的细节:
size:类型为'middle' | 'small' | 'default',若当前组件处于 ConfigProvider 的 size 上下文中且未显式传入,会通过useSize钩子继承全局尺寸(见 index.tsx#L93)。column:支持数字或断点对象两种形式。源码中通过matchScreen(screens, { ...DEFAULT_COLUMN_MAP, ...column }) ?? 3合并计算最终列数(index.tsx#L77-L88),未命中任何断点时兜底为 3 列。官方文档表格中注明 column 的断点对象形式「仅在bordered={true}时生效」。labelStyle/contentStyle(4.10.0 起):通过DescriptionsContext下发给所有 Item 作为「根级」样式,具体优先级见后文「样式定制与覆盖优先级」。
DescriptionItem API 与 span 列宽控制
items数组中的每一项对应以下字段(类型定义见 components/descriptions/Item.ts 与 index.tsx#L23-L29):
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| contentStyle | 自定义内容样式 | CSSProperties | - | 4.9.0 |
| label | 内容的描述 | ReactNode | - | - |
| labelStyle | 自定义标签样式 | CSSProperties | - | 4.9.0 |
| span | 包含的列数 | number | Screens | 1 | screens: 5.9.0 |
关于 span,官方文档有一段重要补充说明:
The number of span Description.Item. Span={2} takes up the width of two DescriptionItems. When both
styleandlabelStyle(orcontentStyle) configured, both of them will work. And next one will overwrite first when conflict.
即:span={2}表示该条目占据两个普通条目的宽度;当style与labelStyle(或contentStyle)同时配置时两者都会生效,发生冲突时后者覆盖前者。这一点与源码 components/descriptions/Cell.tsx#L48-L49 的展开顺序完全一致:labelStyle={{ ...rootLabelStyle, ...labelStyle }}、contentStyle={{ ...rootContentStyle, ...contentStyle }}—— Item 级样式始终覆盖根级(Descriptions 级)样式。
span自 5.9.0 起还支持响应式对象(screens: 5.9.0),例如span={{ xl: 2, xxl: 2 }},会在useItems中通过matchScreen依据当前屏幕断点解析为具体数字(useItems.ts#L24-L31)。
布局与视觉定制:bordered / layout / size / colon / title / extra
边框与尺寸
bordered={true}:开启表格边框。源码中渲染分支发生变化——bordered 模式下每行使用th(label)+td(content)两个独立单元格,无边框模式下 label 与 content 合并在同一个td内通过 flex 布局排布(见 components/descriptions/Row.tsx#L128-L137)。size="middle" | "small":控制单元格内边距。从 components/descriptions/style/index.ts 的样式生成逻辑看,middle 使用paddingSM、small 使用paddingXS,实现紧凑型详情面板。
布局方向
layout="horizontal"(默认):标签与内容同行排列。layout="vertical":标签与内容上下堆叠。源码中 vertical 模式下每个逻辑行会被拆成两行<tr>渲染:第一行只渲染 label(th),第二行只渲染 content(td),见 Row.tsx#L105-L126。
// 来自 demo/vertical.tsx:地址占两列宽度,其余条目单列 const items: DescriptionsProps['items'] = [ { key: '1', label: 'UserName', children: 'Zhou Maomao' }, { key: '2', label: 'Telephone', children: '1810000000' }, { key: '3', label: 'Live', children: 'Hangzhou, Zhejiang' }, { key: '4', label: 'Address', span: 2, children: 'No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China' }, { key: '5', label: 'Remark', children: 'empty' }, ]; <Descriptions title="User Info" layout="vertical" items={items} />;冒号、标题与操作区
colon={false}:隐藏标签后的冒号。样式层通过在 label 元素上追加-item-no-colon类并把::after伪元素内容置空实现(style/index.ts#L182-L184)。title:面板顶部标题,样式上使用fontWeightStrong加粗、fontSizeLG放大(style/index.ts#L131-L138)。extra:右上角操作区(如「编辑」「更多」按钮),通过marginInlineStart: 'auto'推到标题右侧(style/index.ts#L139-L143)。
<Descriptions title="User Info" extra={<Button size="small" type="link">Edit</Button>} items={items} />响应式列数与响应式 span
Descriptions 内置了一套断点默认列数映射,定义在 components/descriptions/constant.ts:
const DEFAULT_COLUMN_MAP: Record<Breakpoint, number> = { xxl: 3, xl: 3, lg: 3, md: 3, sm: 2, xs: 1, };即默认在手机屏(xs)上每行 1 列、平板(sm)2 列、桌面端(md 及以上)3 列。开发者可通过column传入断点对象覆盖任意断点的列数,配合useBreakpoint(grid/hooks/useBreakpoint)实时响应窗口变化。
官方 responsive Demo 给出了完整的多断点实践:column={{ xs: 1, sm: 2, md: 3, lg: 3, xl: 4, xxl: 4 }}让宽屏下每行容纳 4 列;同时条目级span也可以按断点自适应,例如「Config Info」「Hardware Info」两项在窄屏占 1 列、中等屏占 2~3 列、超宽屏占 2 列:
{ label: 'Config Info', span: { xs: 1, sm: 2, md: 3, lg: 3, xl: 2, xxl: 2 }, children: ( <> Data disk type: MongoDB <br /> Database version: 3.4 <br /> Package: dds.mongo.mid </> ), }样式定制与覆盖优先级
- Descriptions 级:
labelStyle/contentStyle(4.10.0)作为根级样式通过DescriptionsContext下发(DescriptionsContext.ts)。 - Item 级:
labelStyle/contentStyle(4.9.0)作用在单个条目上。 - 单元格级:
style作用在整格(td/th)上。
合并顺序在 Cell.tsx#L48-L49 中体现为{ ...root, ...item },因此条目级覆盖根级;文档同时强调style与labelStyle/contentStyle并行生效、冲突时后者(labelStyle/contentStyle)覆盖前者。仓库中的 style Demo 与 padding Demo 展示了具体效果。
源码级原理剖析:从items到表格行的渲染链路
理解 Descriptions 的底层渲染流程,有助于排查 span 越界、列数不符等布局问题。整条链路可概括为四步:
- 列数解析(index.tsx#L77-L88):
mergedColumn合并默认断点映射与用户column,得到当前屏幕下的实际列数。 - 条目归一(useItems.ts):把
items或 children 统一成内部条目数组,并将响应式span对象解析为数字。 - 行计算(useRow.ts):
getCalcRows按列数把条目切分为多个行数组,逐项累计剩余列数rowRestCol;当某条span超出本行剩余列数时,会将该条目的 span 自动收缩为剩余列数并标记exceed,在开发模式下通过devUseWarning输出告警:Sum of column span in a line not match column of Descriptions.。这一机制保证任何 span 配置都不会破坏表格结构。 - 单元格渲染(Row.tsx + Cell.tsx):非 bordered 模式每个条目渲染为单个
td(内部用 flex 容器排列 label 与 content,并通过colSpan={span}扩展宽度);bordered 模式拆分为th+td两个单元格,content 的colSpan为span * 2 - 1;vertical 模式再进一步拆成 label 行与 content 行两行<tr>。
最终 DOM 结构稳定为div.descriptions > div.descriptions-header + div.descriptions-view > table > tbody > tr.descriptions-row,官方测试用例(components/descriptions/tests/index.test.tsx、hooks.test.tsx)对上述行计算与响应式逻辑均有覆盖验证。
Design Token 定制
Descriptions 支持通过主题 Token 统一定制视觉风格,组件的ComponentToken定义于 components/descriptions/style/index.ts#L9-L56,官方文档以<ComponentTokenTable component="Descriptions" />动态渲染完整 Token 表格,源码中可确认的 Token 包括:
| Token | 说明 | 默认值(由prepareComponentToken派生) |
|---|---|---|
| labelBg | 标签背景色(bordered 模式) | colorFillAlter |
| titleColor | 标题文字颜色 | colorText |
| titleMarginBottom | 标题下间距 | fontSizeSM * lineHeightSM |
| itemPaddingBottom | 子项下内边距 | padding |
| itemPaddingEnd | 子项结束(右侧)内边距 | padding |
| colonMarginRight | 冒号右间距 | marginXS |
| colonMarginLeft | 冒号左间距 | marginXXS / 2 |
| contentColor | 内容文字颜色 | colorText |
| extraColor | 额外区域文字颜色 | colorText |
例如在 ConfigProvider 中定制标签背景色与标题颜色:
<ConfigProvider theme={{ components: { Descriptions: { labelBg: '#f5f5f5', titleColor: '#1677ff', contentColor: 'rgba(0, 0, 0, 0.88)', }, }, }} > <Descriptions title="User Info" bordered items={items} /> </ConfigProvider>典型场景速查
仓库 demo 目录 提供了覆盖各场景的完整可运行示例,可对照查阅:
- basic.tsx:最基础的
items用法,搭配title展示用户信息; - border.tsx:
bordered表格样式 + 多条目span组合,典型订单/账单详情; - responsive.tsx:响应式
column与响应式span结合的多端适配方案; - vertical.tsx:
layout="vertical"上下堆叠布局; - size.tsx、padding.tsx:尺寸与内边距调节;
- style.tsx:labelStyle/contentStyle 自定义;
- jsx.tsx:旧版
<Descriptions.Item>JSX 写法对照; - component-token.tsx:Component Token 定制效果。
小结
Descriptions 的核心价值在于用极少的配置把「一组只读字段」编排成结构清晰、天然响应式的信息表格。掌握要点即可应对绝大多数详情页需求:优先使用items数组声明数据(5.8.0+);用数字或断点对象控制column与条目span实现多端自适应;借助labelStyle/contentStyle与 Design Token 完成视觉定制;理解useRow的列数兜底与开发期告警,可快速定位布局异常。如需更完整的参数说明,可直接查阅官方文档 components/descriptions/index.en-US.md 及中文版 index.zh-CN.md。
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考