7.13. 布局与容器组件:构建信息骨架 摘要 :在本章中,我们将学习如何使用 Ant Design 提供的容器与布局组件,将第一阶段学习的各种基础(原子化)信息有效地 组织和包裹 起来。这些组件是构建页面结构、划分信息层级的“骨架”,是从零散元素到完整页面的关键一步。
7.13.1. Card: 信息聚合的基础容器 Card
(卡片) 是 Web UI 中最通用、最基础的内容容器。它的核心价值在于,将一组相关的信息(无论是文字、图片、列表还是图表)收纳在一个独立的、带有视觉边界的矩形区域内,从而为用户提供清晰、规整、易于聚焦的信息区块。
核心应用场景 :
仪表盘(Dashboard) :每一个 KPI 指标、每一个图表,都可以用一个 Card
来承载。内容展示 :文章摘要、商品信息、用户资料,都可以用 Card
来呈现。信息分组 :在复杂的表单或设置页面中,使用 Card
将相关的配置项分组。第一步:基础卡片结构 一个标准的 Card
由头部(title
, extra
)、内容(children
)和底部(actions
)三部分构成。此外,它还内置了加载状态,可以在数据获取期间显示优雅的骨架屏。
核心属性 :
title
: 卡片头部的标题 。extra
: 显示在卡片头部右上角的额外元素,通常是一个链接或操作按钮。actions
: 出现在卡片底部的操作按钮组 ,接收一个 React 节点数组。loading
: 布尔值,当为 true
时,卡片内容区会显示为加载中的骨架屏。hoverable
: 鼠标悬浮时显示阴影,提供可交互的视觉反馈。文件路径 : src/components/demos/BasicCardDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import React from 'react' ;import { Card , Space } from 'antd' ;import { EditOutlined , EllipsisOutlined , SettingOutlined } from '@ant-design/icons' ;const BasicCardDemo : React .FC = () => ( <div className ="p-8 bg-gray-100 rounded-lg shadow-inner" > <h3 className ="text-xl font-bold mb-4 text-center" > 基础卡片结构</h3 > <Space > {/* 1. 一个标准的卡片 */} <Card title ="标准卡片" extra ={ <a href ="#" > 更多</a > } style={{ width: 300 }} hoverable actions={[ <SettingOutlined key ="setting" /> , <EditOutlined key ="edit" /> , <EllipsisOutlined key ="ellipsis" /> , ]} > <p > 这是卡片的内容区。</p > <p > 可以放入任意文本和组件。</p > </Card > {/* 2. 一个加载中的卡片 */} <Card title ="加载中..." extra ={ <a href ="#" > More</a > } style={{ width: 300 }} loading={true} > <p > 这里的内容会被骨架屏替代。</p > </Card > </Space > </div > ); export default BasicCardDemo ;
在 App.tsx
中使用此 Demo :
文件路径 : src/App.tsx
(修改文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import React from 'react' ;import { ConfigProvider } from 'antd' ;import zhCN from 'antd/locale/zh_CN' ;import 'dayjs/locale/zh-cn' ;import BasicCardDemo from './components/demos/BasicCardDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > <BasicCardDemo /> </div > </ConfigProvider > ); }; export default App ;
对于需要展示图片和结构化描述的场景(如文章、商品),Card
提供了 cover
属性和 Card.Meta
子组件来快速构建图文并茂的卡片。
核心属性/组件 :
cover
: 在卡片顶部(标题之下,内容之上)渲染一个封面图片或视频Card.Meta
: 一个用于生成标准元数据布局的辅助组件,它通常包含 avatar
(头像)、title
(标题) 和 description
(描述) 三部分,是 cover
的绝佳搭档。文件路径 : src/components/demos/MetaCardDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import React from 'react' ;import { Avatar , Card } from 'antd' ;import { EditOutlined , EllipsisOutlined , SettingOutlined } from '@ant-design/icons' ;const { Meta } = Card ;const MetaCardDemo : React .FC = () => ( <div className ="p-8 bg-gray-100 rounded-lg shadow-inner" > <h3 className ="text-xl font-bold mb-4 text-center" > 图文卡片 (Meta)</h3 > <Card style ={{ width: 300 }} cover ={ <img alt ="example" src ="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png" /> } actions={[ <SettingOutlined key ="setting" /> , <EditOutlined key ="edit" /> , <EllipsisOutlined key ="ellipsis" /> , ]} > <Meta avatar ={ <Avatar src ="https://api.dicebear.com/7.x/miniavs/svg?seed=1" /> } title="欧洲风情" description="这是对卡片内容的详细描述,展示在标题下方。" /> </Card > </div > ); export default MetaCardDemo ;
在 App.tsx
中切换到新 Demo :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { ConfigProvider } from 'antd' ;import zhCN from 'antd/locale/zh_CN' ;import MetaCardDemo from './components/demos/MetaCardDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > <MetaCardDemo /> </div > </ConfigProvider > ); }; export default App ;
第三步:内部布局 - 网格与内联卡片 Card
不仅能作为外部容器,还提供了 Card.Grid
和 type="inner"
两种方式来组织其 内部 的内容。
1. Card.Grid
(网格型内嵌卡片) Card.Grid
允许您在卡片内部创建一块块 uniform 的网格。每个网格都像一个可点击的、没有边距的迷你卡片,非常适合展示一组同类的入口或项目。
2. type="inner"
(内部卡片) 当您需要在一个 Card
内部,再嵌套一个带有标题和边框的、结构完整的子卡片时,可以为内部的 Card
添加 type="inner"
属性。它会以一种更紧凑、视觉上更协调的样式进行渲染。
文件路径 : src/components/demos/LayoutCardDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import React from "react" ;import { Card } from "antd" ;const LayoutCardDemo : React .FC = () => { const gridData = [ { title : "总访问量" , value : "1234" }, { title : "新用户" , value : "567" }, { title : "订单数" , value : "890" }, { title : "销售额" , value : "12.3K" }, { title : "转化率" , value : "3.2%" }, { title : "活跃用户" , value : "456" }, { title : "增长率" , value : "8.5%" }, { title : "活跃用户" , value : "456" }, ]; return ( <div className ="p-8 bg-gray-100 rounded-lg shadow-inner" > <h3 className ="text-xl font-bold mb-4 text-center" > 内部布局</h3 > {/* 1. 网格型卡片 */} <Card title ="项目仪表盘" className ="mb-4" > {gridData.map((item, index) => ( <Card.Grid key ={index} style ={{ width: "25 %" }}> <div className ="text-center" > <p > {item.title}</p > <p > {item.value}</p > </div > </Card.Grid > ))} </Card > {/* 2. 内部卡片 */} <Card title ="外部卡片" > <p > 这里是外部卡片的内容。</p > <Card type ="inner" title ="内部卡片标题" extra ={ <a href ="#" > 更多</a > }> 这里是内部卡片的内容。 </Card > <Card type ="inner" title ="另一个内部卡片" style ={{ marginTop: 16 }}> 这里是另一个内部卡片的内容。 </Card > </Card > </div > ); }; export default LayoutCardDemo ;
在 App.tsx
中切换到新 Demo :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import LayoutCardDemo from './components/demos/LayoutCardDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > {/* <MetaCardDemo /> */} <LayoutCardDemo /> </div > </ConfigProvider > ); };
通过这三个层层递进的示例,我们掌握了 Card
组件从外到内的全部核心用法。它既能作为承载万物的通用容器,又能通过 Meta
, Grid
等子组件实现精细化的内部布局,是构建结构化页面的绝对主力。
7.13.2. Segmented: 视图切换的开关 Segmented
(分段控制器) 是一个轻量级、现代化的选择控件。它的核心功能是在一组互斥的选项中,提供清晰的单选能力。相比于传统的 Tabs
或 Radio
按钮组,Segmented
在视觉上更紧凑、整体感更强,非常适合用作工具栏中的视图切换器或状态筛选器。
核心应用场景 :
视图切换 :在“地图模式”与“列表模式”之间切换。数据周期选择 :在“日”、“周”、“月”、“年”等时间维度间切换图表数据。状态筛选 :在“全部”、“处理中”、“已完成”等状态间筛选任务列表。第一步:基础用法与视图切换 Segmented
最核心的用途就是通过其值的变化,来驱动页面其他部分内容的条件渲染。这是一个典型的 受控组件 用法。
核心属性 :
options
: 设置分段器的所有选项 。最简单的用法是传入一个字符串数组。value
: 当前选中的值 。该属性需要绑定到一个 React State。onChange
: 选项变化时的回调函数 。当用户点击不同选项时触发,我们需要在此函数中更新 value
绑定的 State。文件路径 : src/components/demos/BasicSegmentedDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import React , { useState } from 'react' ;import { Segmented , Card } from 'antd' ;const ListView = ( ) => <Card style ={{ backgroundColor: '#e6f4ff ' }}> 这是列表视图内容</Card > ;const CardView = ( ) => <Card style ={{ backgroundColor: '#f6ffed ' }}> 这是卡片视图内容</Card > ;const KanbanView = ( ) => <Card style ={{ backgroundColor: '#fffbe6 ' }}> 这是看板视图内容</Card > ;const BasicSegmentedDemo : React .FC = () => { const [currentView, setCurrentView] = useState<string | number >('List' ); const renderView = ( ) => { switch (currentView) { case 'Card' : return <CardView /> ; case 'Kanban' : return <KanbanView /> ; case 'List' : default : return <ListView /> ; } }; return ( <div className ="p-8 bg-white rounded-lg shadow-lg w-[500px]" > <h3 className ="text-xl font-bold mb-4 text-center" > 基础用法与视图切换</h3 > <Segmented options ={[ 'List ', 'Card ', 'Kanban ']} // 3. 传入简单的字符串数组 value ={currentView} // 4. 绑定 state onChange ={setCurrentView} // 5. 传入 state 的更新函数 block // 使分段控制器宽度撑满父容器 /> <div className ="mt-4 p-4 border rounded" > {renderView()} </div > </div > ); }; export default BasicSegmentedDemo ;
在 App.tsx
中使用此 Demo :
文件路径 : src/App.tsx
(修改文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import React from 'react' ;import { ConfigProvider } from 'antd' ;import zhCN from 'antd/locale/zh_CN' ;import 'dayjs/locale/zh-cn' ;import BasicSegmentedDemo from './components/demos/BasicSegmentedDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > <BasicSegmentedDemo /> </div > </ConfigProvider > ); }; export default App ;
这个示例完整地展示了 Segmented
的核心工作流:用户点击选项 -> onChange
触发 -> 更新 state
-> state
变化导致页面重新渲染,从而显示出与新 state
匹配的视图内容。
第二步:自定义渲染 - 图标与复杂选项 当纯文本无法满足需求时,我们可以通过传入一个 对象数组 给 options
属性,来实现更丰富的自定义渲染,例如为选项添加图标,或者禁用某个特定选项。
options
的对象结构 :{ label, value, icon, disabled, className }
label
: 显示的文本或 React 节点 。value
: 该选项的唯一值 。icon
: 在 label
前显示的图标。disabled
: 禁用该选项。文件路径 : src/components/demos/CustomSegmentedDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import React from 'react' ;import { Segmented } from 'antd' ;import { AppstoreOutlined , BarsOutlined , TableOutlined , UserOutlined } from '@ant-design/icons' ;const CustomSegmentedDemo : React .FC = () => ( <div className ="p-8 bg-white rounded-lg shadow-lg" > <h3 className ="text-xl font-bold mb-4 text-center" > 自定义渲染</h3 > <Segmented options ={[ { label: '列表 ', value: 'List ', icon: <BarsOutlined /> , }, { label: '卡片', value: 'Card', icon: <AppstoreOutlined /> , }, { label: '表格', value: 'Table', icon: <TableOutlined /> , disabled: true, // 禁用这个选项 }, { // 只有图标的选项 value: 'User', icon: <UserOutlined /> , }, ]} /> </div > ); export default CustomSegmentedDemo ;
在 App.tsx
中切换到新 Demo :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import CustomSegmentedDemo from './components/demos/CustomSegmentedDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > {/* <BasicSegmentedDemo /> */} <CustomSegmentedDemo /> </div > </ConfigProvider > ); };
通过使用对象数组作为 options
,我们获得了对每个分段项的完全控制权,可以轻松地构建出既美观又功能丰富的选择器,极大地提升了用户交互的清晰度和效率。
7.13.3. Collapse: 折叠收纳的内容面板 Collapse
(折叠面板) 是一种高效的内容组织容器,它允许您将大量信息按逻辑分组,并默认将它们收起,只展示标题。用户可以按需点击标题,展开或收起对应的内容区域。这种交互模式对于保持页面整洁、减少信息过载、让用户聚焦于当前任务至关重要。
核心应用场景 :
FAQ 页面 :将每个“问题”作为面板标题,将“答案”作为可折叠的内容。配置中心 :将复杂的设置项按功能分组,收纳在不同的面板中。版本日志 :展示多个版本的更新记录,用户可以自由展开感兴趣的版本详情。重要升级提示 (v5.6.0+) : 在 antd v5.6.0 之后,官方 强烈推荐 使用 items
属性来数据驱动地配置面板内容。旧有的通过 JSX 嵌套 <Collapse.Panel>
的写法已被废弃。本教程将完全遵循 2025 年的最佳实践,只使用现代的 items
写法。
第一步:基础用法与数据驱动 (items
) 创建 Collapse
组件的最佳方式是为其提供一个 items
数组。数组中的每一个对象都代表一个可折叠的面板,这种数据驱动的方式让代码更清晰、更易于维护。
核心属性 :
items
: 一个对象数组,用于定义所有面板。每个对象的核心结构为:key
: 每个面板的唯一标识符。label
: 显示在面板头部的标题内容。children
: 折叠区域内的主体内容。defaultActiveKey
: 一个包含 key
的数组,用于指定初始状态下哪些面板是展开的。onChange
: 当展开的面板发生变化时触发的回调,参数为当前所有展开面板的 key
组成的数组。文件路径 : src/components/demos/BasicCollapseDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import React from 'react' ;import { Collapse } from 'antd' ;import type { CollapseProps } from 'antd' ;const text = ` Ant Design, a design language for background applications, is refined by Ant UED Team. It is a set of enterprise-class UI design language and React UI library with a set of easy-to-use demos. ` ;const items : CollapseProps ['items' ] = [ { key : '1' , label : '这是面板标题 1' , children : <p > {text}</p > , }, { key : '2' , label : '这是面板标题 2' , children : <p > {text}</p > , }, { key : '3' , label : '这是面板标题 3' , children : <p > {text}</p > , }, ]; const BasicCollapseDemo : React .FC = () => { const onChange = (key : string | string [] ) => { console .log ('当前展开的面板 key:' , key); }; return ( <div className ="p-8 bg-white rounded-lg shadow-lg w-[600px]" > <h3 className ="text-xl font-bold mb-4 text-center" > 基础折叠面板</h3 > <Collapse items ={items} defaultActiveKey ={[ '1 ']} onChange ={onChange} /> </div > ); }; export default BasicCollapseDemo ;
在 App.tsx
中使用此 Demo :
文件路径 : src/App.tsx
(修改文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import React from 'react' ;import { ConfigProvider } from 'antd' ;import zhCN from 'antd/locale/zh_CN' ;import 'dayjs/locale/zh-cn' ;import BasicCollapseDemo from './components/demos/BasicCollapseDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > <BasicCollapseDemo /> </div > </ConfigProvider > ); }; export default App ;
第二步:手风琴模式与自定义 除了允许多个面板同时展开,Collapse
还支持一种特殊的“手风琴”模式,即 任何时候只允许一个面板展开 。同时,我们还可以通过其他属性对样式和内容进行自定义。
核心属性 :
accordion
: {布尔值,设置为 true
即可开启手风琴模式。bordered
: 布尔值,设置是否显示边框,false
可创建更简洁的外观。extra
: 在 items
的对象中定义,用于在面板头的右上角添加额外节点(如图标或操作按钮)。expandIconPosition
: 设置展开/收起图标的位置,可选 start
或 end
。文件路径 : src/components/demos/AccordionCollapseDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import React from 'react' ;import { Collapse , Space } from 'antd' ;import type { CollapseProps } from 'antd' ;import { SettingOutlined } from '@ant-design/icons' ;const text = ` A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome guest in many households across the world. ` ;const getItems = (extraNode : React .ReactNode ): CollapseProps ['items' ] => [ { key : '1' , label : '面板 1' , children : <p > {text}</p > , extra : extraNode, }, { key : '2' , label : '面板 2' , children : <p > {text}</p > , extra : extraNode, }, { key : '3' , label : '面板 3 (不可展开)' , children : <p > {text}</p > , collapsible : 'disabled' , }, ]; const AccordionCollapseDemo : React .FC = () => ( <div className ="p-8 bg-white rounded-lg shadow-lg w-[600px]" > <h3 className ="text-xl font-bold mb-4 text-center" > 手风琴模式与自定义</h3 > <Space direction ="vertical" style ={{width: '100 %'}}> <p > 手风琴模式 (Accordion)</p > <Collapse accordion items ={getItems( <SettingOutlined /> )} /> <p className ='mt-4' > 无边框样式 (bordered=false)</p > <Collapse bordered ={false} defaultActiveKey ={[ '1 ']} items ={getItems( <SettingOutlined /> )} /> <p className ='mt-4' > 图标位置 (expandIconPosition='end')</p > <Collapse expandIconPosition ="end" defaultActiveKey ={[ '1 ']} items ={getItems( <SettingOutlined /> )} /> </Space > </div > ); export default AccordionCollapseDemo ;
在 App.tsx
中切换到新 Demo :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import AccordionCollapseDemo from './components/demos/AccordionCollapseDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > {/* <BasicCollapseDemo /> */} <AccordionCollapseDemo /> </div > </ConfigProvider > ); };
通过 accordion
属性,我们可以轻松切换折叠面板的核心交互模式。结合 bordered
、extra
等自定义属性,Collapse
能够灵活地适应各种信息收纳场景,是优化长页面内容展示、提升信息架构清晰度的得力工具。
7.13.4. Descriptions: 结构化的详情展示 Descriptions
(描述列表) 是一个专为 展示键值对(Key-Value)信息 而设计的组件。当您需要在一个详情页或弹窗中,清晰、整齐地陈列多个只读字段时,Descriptions
能够自动处理对齐、列分布和响应式布局,省去了手动编写表格或栅格布局的繁琐工作。
核心应用场景 :
用户详情页 :展示用户的姓名、电话、邮箱、地址等。订单详情 :展示订单号、下单时间、支付状态、收货地址等。系统信息 :展示应用的名称、版本号、服务器 IP、运行状态等。重要升级提示 (v5.8.0+) : 在 antd v5.8.0 之后,官方 强烈推荐 使用 items
属性来数据驱动地配置描述列表。旧有的通过 JSX 嵌套 <Descriptions.Item>
的写法已被废弃。本教程将完全遵循 2025 年的最佳实践,只使用现代的 items
写法。
第一步:基础用法与 span
布局 创建 Descriptions
的最佳方式是为其提供一个 items
数组。其布局基于一个响应式的网格系统,我们可以通过 column
和 span
属性来精确控制每一项的排列。
核心属性 :
title
: 描述列表的整体标题items
: 一个对象数组,用于定义所有描述项。每个对象的核心结构为:key
: 唯一标识符。label
: 描述项的标签(Key)。children
: 描述项的内容(Value)。span
: 该项占据的 列数 。column
: 描述列表的总列数,默认为 3。所有 items
的 span
值将在这个总列数内进行分配。文件路径 : src/components/demos/BasicDescriptionsDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import React from "react" ;import { Descriptions } from "antd" ;import type { DescriptionsProps } from "antd" ;const BasicDescriptionsDemo : React .FC = () => { const items : DescriptionsProps ["items" ] = [ { key : "1" , label : "产品名称" , children : "Ant Design Pro" }, { key : "2" , label : "计费模式" , children : "预付费" }, { key : "3" , label : "创建时间" , children : "2023-01-10" }, { key : "4" , label : "关联订单" , children : "123456789" }, { key : "5" , label : "生效时间" , children : "2023-01-10" }, { key : "6" , label : "配置信息" , span : 2 , children : ( <> CPU: 4 核<br /> 内存: 16 GB <br /> 带宽: 5 Mbps </> ), }, { key : "7" , label : "备注" , children : "无" }, ]; return ( <div className ="p-8 bg-white rounded-lg shadow-lg w-[800px]" > <h3 className ="text-xl font-bold mb-4 text-center" > 基础用法</h3 > <Descriptions items ={items} column ={3} title ="产品配置详情" /> </div > ); }; export default BasicDescriptionsDemo ;
在 App.tsx
中使用此 Demo :
文件路径 : src/App.tsx
(修改文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import React from 'react' ;import { ConfigProvider } from 'antd' ;import zhCN from 'antd/locale/zh_CN' ;import 'dayjs/locale/zh-cn' ;import BasicDescriptionsDemo from './components/demos/BasicDescriptionsDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > <BasicDescriptionsDemo /> </div > </ConfigProvider > ); }; export default App ;
第二步:布局与样式 - 边框、垂直与尺寸 除了默认的无边框、水平布局,Descriptions
还提供了多种样式变体,以适应不同的展示需求,例如更正式的、类似表格的带边框样式。
核心属性 :
bordered
: 布尔值,设置为 true
可为描述列表添加边框和背景色,使其外观类似表格。layout
: 布局方式,可选 horizontal
(水平,默认) 或 vertical
(垂直,标签在内容上方)。size
: 设置列表的尺寸,可选 default
, middle
, small
。此属性仅在 bordered={true}
时生效 ,用于创建更紧凑的列表。extra
: 在 title
同一行的右上角添加额外操作区,例如一个“编辑”按钮。文件路径 : src/components/demos/StyledDescriptionsDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import React from 'react' ;import { Descriptions , Badge , Button } from 'antd' ;import type { DescriptionsProps } from 'antd' ;const items : DescriptionsProps ['items' ] = [ { key : '1' , label : '产品' , children : '云服务器 ECS' }, { key : '2' , label : '计费模式' , children : '按量付费' }, { key : '3' , label : '自动续费' , children : '是' }, { key : '4' , label : '订单号' , children : '1234567890' }, { key : '5' , label : '创建时间' , children : '2023-01-10 18:00:00' }, { key : '6' , label : '状态' , span : 3 , children : <Badge status ="processing" text ="运行中" /> }, { key : '7' , label : '折扣' , children : '¥ 20.00' }, { key : '8' , label : '总计' , children : '¥ 60.00' }, { key : '9' , label : '实付' , children : '¥ 40.00' }, ]; const StyledDescriptionsDemo : React .FC = () => ( <div className ="p-8 bg-white rounded-lg shadow-lg w-[800px]" > <h3 className ="text-xl font-bold mb-4 text-center" > 布局与样式</h3 > {/* 1. 带边框的样式 */} <Descriptions title ="订单详情 (带边框)" bordered extra ={ <Button type ="primary" > 编辑</Button > } items={items} className="mb-8" /> {/* 2. 垂直布局 + 小尺寸 */} <Descriptions title ="订单详情 (垂直 + 小尺寸)" bordered layout ="vertical" size ="small" items ={items} /> </div > ); export default StyledDescriptionsDemo ;
在 App.tsx
中切换到新 Demo :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import StyledDescriptionsDemo from './components/demos/StyledDescriptionsDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > {/* <BasicDescriptionsDemo /> */} <StyledDescriptionsDemo /> </div > </ConfigProvider > ); };
通过 bordered
, layout
, size
等属性的组合,Descriptions
能够灵活地在“简洁信息列表”和“正式详情表格”两种风格之间切换。其数据驱动的 items
API 和强大的 span
布局能力,使其成为详情页开发中不可或缺的效率工具。
7.13.5. Carousel: 动态轮播的内容容器 Carousel
(走马灯),在网页设计中通常也被称为“Slider”或“轮播图”,是一种在有限的界面空间内,循环展示多个内容面板(通常是图片或卡片)的容器组件。它通过自动或手动切换,有效地利用了黄金展示区域,是官网首页、产品宣传等场景的理想选择。
核心应用场景 :
网站首页 Banner :轮播展示最新的活动、产品或新闻。产品图集 :在商品详情页,以轮播形式展示多张高清图片。功能介绍 :在新用户引导流程中,轮播展示核心功能的介绍卡片。第一步:基础用法与切换效果 创建一个 Carousel
非常简单,您只需将需要轮播的各个面板作为其 children
传入即可。同时,Carousel
也提供了多种切换效果和指示器位置的配置。
核心属性 :
children
: 需要轮播的 React 节点数组。每个直接子元素都会被视为一个独立的面板。effect
: 切换的动画效果。可选值为 'scrollx'
(水平滚动,默认) 或 'fade'
(淡入淡出)。dotPosition
: 面板指示点(小圆点)的位置,可选 top
, bottom
(默认), left
, right
。文件路径 : src/components/demos/BasicCarouselDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import React from "react" ;import { Carousel , Divider } from "antd" ;const contentStyle : React .CSSProperties = { margin : 0 , height : "160px" , color : "#fff" , lineHeight : "160px" , textAlign : "center" , background : "#364d79" , }; const BasicCarouselDemo : React .FC = () => ( <div className ="p-8 bg-white rounded-lg shadow-lg w-[600px]" > <h3 className ="text-xl font-bold mb-4 text-center" > 基础用法与切换效果</h3 > <Divider orientation ="left" > 默认滚动效果 (scrollx)</Divider > <Carousel autoplay > <div > <h3 style ={contentStyle} > 面板 1</h3 > </div > <div > <h3 style ={contentStyle} > 面板 2</h3 > </div > <div > <h3 style ={contentStyle} > 面板 3</h3 > </div > </Carousel > <Divider orientation ="left" > 垂直滚动效果 (vertical)</Divider > <Carousel vertical autoplay > <div > <h3 style ={contentStyle} > 面板 1</h3 > </div > <div > <h3 style ={contentStyle} > 面板 2</h3 > </div > </Carousel > <Carousel effect ="fade" autoplay > <div > <h3 style ={contentStyle} > 面板 1</h3 > </div > <div > <h3 style ={{...contentStyle, background: '#5a8d9b '}}> 面板 2</h3 > </div > <div > <h3 style ={{...contentStyle, background: '#8ab4c2 '}}> 面板 3</h3 > </div > </Carousel > </div > ); export default BasicCarouselDemo ;
在 App.tsx
中使用此 Demo :
文件路径 : src/App.tsx
(修改文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import React from 'react' ;import { ConfigProvider } from 'antd' ;import zhCN from 'antd/locale/zh_CN' ;import 'dayjs/locale/zh-cn' ;import BasicCarouselDemo from './components/demos/BasicCarouselDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > <BasicCarouselDemo /> </div > </ConfigProvider > ); }; export default App ;
第二步:自动播放与程序化控制 在大多数场景下,我们希望走马灯能够自动播放。有时,我们还需要通过外部的按钮来手动控制其切换,这就需要使用 ref
来获取 Carousel
实例并调用其方法。
核心属性/方法 :
autoplay
: 布尔值,设置为 true
即可开启自动播放。ref
: 用于获取 Carousel
组件的实例。ref.current.next()
: 切换到下一个面板。ref.current.prev()
: 切换到上一个面板。ref.current.goTo(slideNumber)
: 跳转到指定索引的面板。文件路径 : src/components/demos/ControlledCarouselDemo.tsx
(新建文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import React , { useRef } from 'react' ;import { Carousel , Button , Space , Divider } from 'antd' ;import type { CarouselRef } from 'antd/es/carousel' ;const contentStyle : React .CSSProperties = { margin : 0 , height : '160px' , color : '#fff' , lineHeight : '160px' , textAlign : 'center' , background : '#364d79' , }; const ControlledCarouselDemo : React .FC = () => { const carouselRef = useRef<CarouselRef >(null ); const handleNext = ( ) => { carouselRef.current ?.next (); }; const handlePrev = ( ) => { carouselRef.current ?.prev (); }; const handleGoTo = ( ) => { carouselRef.current ?.goTo (0 ); } return ( <div className ="p-8 bg-white rounded-lg shadow-lg w-[600px]" > <h3 className ="text-xl font-bold mb-4 text-center" > 自动播放与手动控制</h3 > <Divider orientation ="left" > 自动播放</Divider > <Carousel autoplay > <div > <h3 style ={contentStyle} > 面板 1</h3 > </div > <div > <h3 style ={contentStyle} > 面板 2</h3 > </div > <div > <h3 style ={contentStyle} > 面板 3</h3 > </div > </Carousel > <Divider orientation ="left" > 程序化控制</Divider > <Carousel ref ={carouselRef} > <div > <h3 style ={contentStyle} > 面板 1</h3 > </div > <div > <h3 style ={{...contentStyle, background: '#5a8d9b '}}> 面板 2</h3 > </div > <div > <h3 style ={{...contentStyle, background: '#8ab4c2 '}}> 面板 3</h3 > </div > </Carousel > <Space className ="mt-4" > <Button onClick ={handlePrev} > 上一张</Button > <Button onClick ={handleNext} > 下一张</Button > <Button onClick ={handleGoTo} > 回到第一张</Button > </Space > </div > ); }; export default ControlledCarouselDemo ;
在 App.tsx
中切换到新 Demo :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import ControlledCarouselDemo from './components/demos/ControlledCarouselDemo' ;const App : React .FC = () => { return ( <ConfigProvider locale ={zhCN} > <div className ="bg-gray-100 min-h-screen p-8 flex items-center justify-center" > {/* <BasicCarouselDemo /> */} <ControlledCarouselDemo /> </div > </ConfigProvider > ); };
通过 autoplay
属性和 ref
的程序化控制,我们可以灵活地管理 Carousel
的动态行为,使其既能自动展示内容,也能响应用户的自定义交互。
至此,我们已经完成了第二阶段所有核心容器组件的学习。我们学会了如何使用 Card
聚合信息,用 Collapse
和 Descriptions
组织详情,以及用 Carousel
动态轮播内容。接下来,我们将进入 阶段三:高级数据组件 ,挑战 List
, Table
等功能更强大的组件。