#ProList - 高级列表
ProList 基于 ProTable 实现,可以认为是 ProTable 的一个特例,将数据以列表的形式展现。API 设计上更像 Table,使得 Table 和 List 的切换变得更加容易。
#何时使用
当你需要一个标准的列表展现,或需要在列表和表格之间灵活切换时,ProList 是不二选择。
#代码演示
#Issue 回归场景
等待请求完成- 第 0-0 条/总共 0 条
- 1
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProCard, ProList } from '@ant-design/pro-components';
import { Alert, Button, Space, Typography } from 'antd';
import { useRef, useState } from 'react';
type Item = { id: number; title: string; description: string };
const columns: ProColumns<Item>[] = [
{ dataIndex: 'title', title: '标题', listSlot: 'title' },
{ dataIndex: 'description', title: '说明', listSlot: 'description' },
{
title: '操作',
listSlot: 'actions',
render: () => [<a key="edit">编辑</a>],
},
];
export default () => {
const actionRef = useRef<ActionType>();
const [pageInfo, setPageInfo] = useState('等待请求完成');
return (
<ProCard direction="column" ghost gutter={[0, 16]}>
<Alert
type="info"
showIcon
message="ProList 展示与实时分页状态"
description="覆盖操作区 hover、grid itemRender gutter 及 actionRef.pageInfo。"
/>
<ProList<Item>
actionRef={actionRef}
rowKey="id"
columns={columns}
showActions="hover"
grid={{ column: 2, gutter: [16, 24] }}
pagination={{ pageSize: 2 }}
request={async () => ({
success: true,
total: 42,
data: [
{ id: 1, title: '项目 A', description: '悬停显示操作区' },
{ id: 2, title: '项目 B', description: '卡片间距保持一致' },
],
})}
itemRender={(item, index, defaultDom) => (
<ProCard title={`自定义 itemRender ${index + 1}`}>
{defaultDom}
</ProCard>
)}
toolBarRender={() => [
<Space key="page-info">
<Button
onClick={() =>
setPageInfo(JSON.stringify(actionRef.current?.pageInfo))
}
>
读取 pageInfo
</Button>
<Typography.Text code>{pageInfo}</Typography.Text>
</Space>,
]}
/>
</ProCard>
);
};
#枚举属性切换
通过 Segmented 分段选择器切换 itemLayout、variant、split 属性。
import { ProList } from '@ant-design/pro-components';
import { Button, Progress, Segmented, Space, Tag } from 'antd';
import { useState } from 'react';
type ProjectItem = {
title: string;
avatar: string;
description: string;
progress: number;
status: string;
};
const dataSource: ProjectItem[] = [
{
title: '智慧零售平台',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '面向线下门店的数字化经营解决方案',
progress: 85,
status: '开发中',
},
{
title: 'Ant Design Pro',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '开箱即用的中台前端解决方案',
progress: 100,
status: '已上线',
},
{
title: '云原生微服务框架',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '基于 K8s 的微服务开发与治理框架',
progress: 92,
status: '测试中',
},
{
title: '数据可视化引擎',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '企业级数据看板与图表分析工具',
progress: 60,
status: '开发中',
},
];
const Demo = () => {
const [itemLayout, setItemLayout] = useState<'horizontal' | 'vertical'>(
'horizontal',
);
const [variant, setVariant] = useState<'outlined' | 'borderless' | 'filled'>(
'borderless',
);
const [split, setSplit] = useState(true);
return (
<div
style={{
background: '#ddd',
padding: 24,
}}
>
<Space
orientation="vertical"
size={12}
style={{
width: '100%',
marginBlockEnd: 16,
padding: 16,
background: '#ddd',
border: '1px solid #f0f0f0',
borderRadius: 8,
}}
>
<Space>
<span>itemLayout 列表项方向:</span>
<Segmented
value={itemLayout}
onChange={(v) => setItemLayout(v as any)}
options={[
{ label: '水平 horizontal', value: 'horizontal' },
{ label: '垂直 vertical', value: 'vertical' },
]}
/>
</Space>
<Space>
<span>variant 外观变体:</span>
<Segmented
value={variant}
onChange={(v) => setVariant(v as any)}
options={[
{ label: '线框 outlined', value: 'outlined' },
{ label: '填充 filled', value: 'filled' },
{ label: '无边框 borderless', value: 'borderless' },
]}
/>
</Space>
<Space>
<span>split 分割线:</span>
<Segmented
value={split ? 'true' : 'false'}
onChange={(v) => setSplit(v === 'true')}
options={[
{ label: '有分割线', value: 'true' },
{ label: '无分割线', value: 'false' },
]}
/>
</Space>
</Space>
<ProList<ProjectItem>
headerTitle="项目列表枚举切换"
itemLayout={itemLayout}
variant={variant}
split={split}
dataSource={dataSource}
rowKey="title"
toolBarRender={() => [
<Button key="new" type="primary">
新建项目
</Button>,
]}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{ dataIndex: 'avatar', listSlot: 'avatar' },
{ dataIndex: 'description', listSlot: 'description' },
{
listSlot: 'content',
render: (_, record) => (
<div style={{ width: 200 }}>
<div>
{record.status}{' '}
<Tag
color={record.progress === 100 ? 'success' : 'processing'}
>
{record.progress}%
</Tag>
</div>
<Progress percent={record.progress} showInfo={false} />
</div>
),
},
{
listSlot: 'actions',
render: () => [
<a key="view">查看</a>,
<a key="edit">编辑</a>,
<a key="archive">归档</a>,
],
},
]}
/>
</div>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#基本使用
import type { ProColumns } from '@ant-design/pro-components';
import { ProList } from '@ant-design/pro-components';
import { Avatar, Space, Tag } from 'antd';
type ProjectItem = {
id: string;
name: string;
description: string;
status: 'active' | 'archived' | 'pending';
owner: {
name: string;
avatar: string;
};
tags: string[];
updatedAt: string;
};
const statusMap = {
active: { text: '进行中', color: 'success' },
archived: { text: '已归档', color: 'default' },
pending: { text: '待启动', color: 'warning' },
};
const dataSource: ProjectItem[] = [
{
id: '1',
name: 'Ant Design Pro',
description: '开箱即用的中台前端/设计解决方案',
status: 'active',
owner: {
name: '书琰',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
},
tags: ['React', 'TypeScript', 'Ant Design'],
updatedAt: '2024-02-09',
},
{
id: '2',
name: 'ProComponents',
description: '专业级别的中后台组件库',
status: 'active',
owner: {
name: '逄一',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
tags: ['React', 'Components'],
updatedAt: '2024-02-08',
},
{
id: '3',
name: 'UmiJS',
description: '插件化的企业级前端应用框架',
status: 'active',
owner: {
name: '期贤',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
},
tags: ['Framework', 'React'],
updatedAt: '2024-02-07',
},
{
id: '4',
name: 'Ant Design Mobile',
description: '移动端设计规范和组件库',
status: 'pending',
owner: {
name: '玄霜',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
tags: ['Mobile', 'React'],
updatedAt: '2024-02-06',
},
{
id: '5',
name: 'Ant Design Charts',
description: '简单好用的 React 图表库',
status: 'archived',
owner: {
name: '怀渊',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
},
tags: ['Charts', 'Visualization'],
updatedAt: '2024-02-05',
},
];
const columns: ProColumns<ProjectItem>[] = [
{
title: '项目名称',
dataIndex: 'name',
listSlot: 'title',
},
{
title: '描述',
dataIndex: 'description',
listSlot: 'description',
},
{
title: '负责人',
dataIndex: ['owner', 'avatar'],
listSlot: 'avatar',
render: (_, record) => (
<Avatar src={record.owner.avatar} alt={record.owner.name} />
),
},
{
title: '状态',
dataIndex: 'status',
listSlot: 'subTitle',
render: (_, record) => (
<Tag color={statusMap[record.status].color}>
{statusMap[record.status].text}
</Tag>
),
},
{
title: '标签',
dataIndex: 'tags',
listSlot: 'content',
render: (_, record) => (
<Space size={4} wrap>
{record.tags.map((tag) => (
<Tag key={tag}>{tag}</Tag>
))}
</Space>
),
},
{
title: '操作',
listSlot: 'actions',
render: () => [<a key="view">查看</a>, <a key="edit">编辑</a>],
},
];
export default () => (
<ProList<ProjectItem>
columns={columns}
dataSource={dataSource}
rowKey="id"
headerTitle="项目列表"
tooltip="这是一个基础的列表示例,展示了 ProList 的基本用法"
/>
);
#使用 columns + listSlot(推荐)
通过 columns 配合 listSlot 属性,可以和 ProTable 共用同一份列配置。listSlot 指定该列映射到列表项的哪个插槽(如 title、avatar、description 等)。
/**
* 使用 columns + listSlot 的新 API,与 ProTable 兼容
*/
import type { ProColumns } from '@ant-design/pro-components';
import { ProList } from '@ant-design/pro-components';
import { Button, Space, Tag } from 'antd';
import type { Key } from 'react';
import { useState } from 'react';
type DataItem = {
id: string;
name: string;
image: string;
desc: string;
labels: string[];
};
const dataSource: DataItem[] = [
{
id: '1',
name: '智慧零售平台',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: 'Ant Design, a design language for background applications, is refined by Ant UED Team',
labels: ['技术专栏', '设计语言'],
},
{
id: '2',
name: 'Ant Design',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '企业级数据看板与可视化分析工具,开箱即用的图表方案',
labels: ['Ant Design', '可视化'],
},
{
id: '3',
name: '云原生微服务框架',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '基于 K8s 的微服务开发与治理框架,支持服务注册与发现',
labels: ['云原生'],
},
{
id: '4',
name: '数据可视化引擎',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '面向企业级中后台的数据可视化解决方案',
labels: ['可视化'],
},
];
/**
* 同一份 columns 可同时用于 ProTable 和 ProList
* ProTable 忽略 listSlot,ProList 使用 listSlot 映射到列表项的各个部分
*/
const columns: ProColumns<DataItem>[] = [
{
title: '名称',
dataIndex: 'name',
listSlot: 'title',
},
{
dataIndex: 'image',
listSlot: 'avatar',
search: false,
},
{
title: '标签',
dataIndex: 'labels',
listSlot: 'subTitle',
search: false,
render: (_, row) => (
<Space size={8}>
{row.labels?.map((label) => (
<Tag color="blue" key={label}>
{label}
</Tag>
))}
</Space>
),
},
{
title: '描述',
dataIndex: 'desc',
listSlot: 'description',
search: false,
},
{
title: '操作',
listSlot: 'actions',
search: false,
render: () => [<a key="edit">编辑</a>, <a key="delete">删除</a>],
},
];
const Demo = () => {
const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
return (
<ProList<DataItem>
rowKey="id"
headerTitle="columns API(与 ProTable 兼容)"
toolBarRender={() => [
<Button key="add" type="primary">
新建
</Button>,
]}
columns={columns}
expandable={{
expandedRowKeys,
onExpandedRowsChange: setExpandedRowKeys,
}}
dataSource={dataSource}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#卡片列表(columns + listSlot)
- 第 1-8 条/总共 8 条
- 1
/**
* 卡片模式使用 columns + listSlot,推荐使用新的 columns API
* actions 在卡片模式下默认渲染到 extra 位置
*/
import type { ProColumns } from '@ant-design/pro-components';
import { ProList } from '@ant-design/pro-components';
import { Alert, Tag } from 'antd';
type DataItem = {
id: string;
title: string;
category: string;
description: string;
avatar: string;
downloads: number;
rating: number;
status: 'stable' | 'beta' | 'deprecated';
};
const statusConfig = {
stable: { text: '稳定版', color: 'success' },
beta: { text: '测试版', color: 'processing' },
deprecated: { text: '已废弃', color: 'default' },
};
const data: DataItem[] = [
{
id: '1',
title: 'ProTable',
category: '表格组件',
description: '高级表格组件,支持搜索、筛选、排序等功能',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/upvrAjAPQX/Logo_Tech%252520UI.svg',
downloads: 125000,
rating: 4.8,
status: 'stable',
},
{
id: '2',
title: 'ProForm',
category: '表单组件',
description: '高级表单组件,简化表单开发流程',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
downloads: 98000,
rating: 4.9,
status: 'stable',
},
{
id: '3',
title: 'ProLayout',
category: '布局组件',
description: '开箱即用的中后台布局方案',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
downloads: 156000,
rating: 4.7,
status: 'stable',
},
{
id: '4',
title: 'ProCard',
category: '卡片组件',
description: '可分割的卡片组件,支持多种布局',
avatar: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
downloads: 67000,
rating: 4.6,
status: 'stable',
},
{
id: '5',
title: 'ProDescriptions',
category: '描述列表',
description: '高级描述列表组件,支持编辑和请求',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/upvrAjAPQX/Logo_Tech%252520UI.svg',
downloads: 45000,
rating: 4.5,
status: 'stable',
},
{
id: '6',
title: 'ProList',
category: '列表组件',
description: '高级列表组件,支持多种展示模式',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
downloads: 52000,
rating: 4.7,
status: 'stable',
},
{
id: '7',
title: 'ProSkeleton',
category: '骨架屏',
description: '高级骨架屏组件,更好的加载体验',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
downloads: 34000,
rating: 4.4,
status: 'beta',
},
{
id: '8',
title: 'ProField',
category: '字段组件',
description: '统一的字段渲染组件',
avatar: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
downloads: 28000,
rating: 4.3,
status: 'stable',
},
];
export default () => {
const columns: ProColumns<DataItem>[] = [
{
title: '组件名称',
dataIndex: 'title',
listSlot: 'title',
},
{
title: '状态',
dataIndex: 'status',
listSlot: 'subTitle',
render: (_, record) => (
<Tag color={statusConfig[record.status].color}>
{statusConfig[record.status].text}
</Tag>
),
},
{
title: '图标',
dataIndex: 'avatar',
listSlot: 'avatar',
},
{
title: '内容',
listSlot: 'content',
render: (_, record) => (
<div style={{ flex: 1 }}>
<div style={{ marginBottom: 8 }}>{record.description}</div>
<div style={{ color: '#999', fontSize: 12 }}>
{record.category} • {(record.downloads / 1000).toFixed(1)}K 下载 •
⭐ {record.rating}
</div>
</div>
),
},
{
title: '操作',
listSlot: 'actions',
render: () => [<a key="install">安装</a>, <a key="docs">文档</a>],
},
];
return (
<div
style={{
backgroundColor: '#eee',
margin: -24,
padding: 24,
}}
>
<Alert
title="推荐使用 columns + listSlot API"
description="新的 columns API 与 ProTable 保持一致,通过 listSlot 指定数据在列表项中的位置。相比 metas API 更加灵活和易于维护。"
type="info"
showIcon
style={{ marginBottom: 16 }}
/>
<ProList<DataItem>
pagination={{ defaultPageSize: 8, showSizeChanger: false }}
rowSelection={{}}
grid={{ gutter: 16, column: 2 }}
columns={columns}
headerTitle="卡片列表(columns API)"
dataSource={data}
/>
</div>
);
};
#网格配置
<ProList
grid={{ gutter: 8, column: 2 }}
itemCardProps={{ bordered: true, ghost: false }}
...
/>- 第 1-12 条/总共 12 条
- 1
- 12 条/页
import { ProList } from '@ant-design/pro-components';
import { Alert, Card, Col, Row, Segmented, Slider, Switch, Tag } from 'antd';
import { useState } from 'react';
const apps = [
{
id: '1',
name: 'Analytics Pro',
category: '数据分析',
description: '企业级数据分析平台,支持多维度数据分析和可视化展示',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
status: 'active',
users: 1280,
},
{
id: '2',
name: 'Cloud Storage',
category: '云存储',
description: '安全可靠的企业云存储服务,支持文件同步和共享',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
status: 'active',
users: 3450,
},
{
id: '3',
name: 'Task Manager',
category: '项目管理',
description: '高效的任务和项目管理工具,支持团队协作和进度跟踪',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
status: 'active',
users: 2150,
},
{
id: '4',
name: 'Email Suite',
category: '企业邮箱',
description: '专业的企业邮件服务,支持大附件和邮件加密',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
status: 'beta',
users: 890,
},
{
id: '5',
name: 'Video Conference',
category: '视频会议',
description: '高清视频会议系统,支持屏幕共享和实时字幕',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
status: 'active',
users: 5200,
},
{
id: '6',
name: 'HR System',
category: '人力资源',
description: '一体化人力资源管理系统,涵盖招聘、考勤、薪酬等',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
status: 'active',
users: 1560,
},
{
id: '7',
name: 'CRM Platform',
category: '客户关系',
description: '智能客户关系管理平台,助力销售业绩提升',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
status: 'active',
users: 2890,
},
{
id: '8',
name: 'Finance Suite',
category: '财务管理',
description: '专业的财务管理系统,支持多币种和自动对账',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
status: 'active',
users: 1120,
},
{
id: '9',
name: 'Workflow Engine',
category: '流程引擎',
description: '灵活的工作流引擎,支持可视化流程设计',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
status: 'beta',
users: 670,
},
{
id: '10',
name: 'Knowledge Base',
category: '知识库',
description: '企业知识管理系统,支持全文检索和智能推荐',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
status: 'active',
users: 1940,
},
{
id: '11',
name: 'Security Center',
category: '安全中心',
description: '企业安全管理中心,实时监控和威胁检测',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
status: 'active',
users: 780,
},
{
id: '12',
name: 'API Gateway',
category: '接口网关',
description: '统一的 API 网关服务,支持流量控制和监控',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
status: 'beta',
users: 450,
},
];
const statusMap: Record<string, { text: string; color: string }> = {
active: { text: '运行中', color: 'success' },
beta: { text: '测试中', color: 'processing' },
};
const data = apps.map((app) => ({
id: app.id,
title: app.name,
subTitle: (
<Tag color={statusMap[app.status].color}>{statusMap[app.status].text}</Tag>
),
actions: [<a key="view">打开</a>, <a key="settings">设置</a>],
avatar: app.icon,
content: (
<div>
<div>{app.description}</div>
<div style={{ color: '#999', fontSize: 12, marginTop: 8 }}>
{app.category} • {app.users.toLocaleString()} 用户
</div>
</div>
),
}));
export default () => {
const [column, setColumn] = useState<number>(2);
const [gutter, setGutter] = useState<number>(8);
const [bordered, setBordered] = useState<boolean>(true);
const [ghost, setGhost] = useState<boolean>(false);
return (
<div style={{ padding: 24, backgroundColor: '#f5f5f5' }}>
<Alert
title="Grid 布局配置"
description="ProList 使用 CSS Grid 实现网格布局,支持自定义列数和间距。通过 grid 属性配置,可以实现响应式的卡片网格布局。"
type="info"
showIcon
style={{ marginBottom: 24 }}
/>
<Card title="配置面板" style={{ marginBottom: 24 }}>
<Row gutter={[24, 24]}>
<Col xs={24} md={12}>
<div>
<div style={{ marginBottom: 8, fontWeight: 500 }}>
列数 (column): {column}
</div>
<Slider
min={1}
max={6}
value={column}
onChange={setColumn}
marks={{
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
}}
/>
</div>
</Col>
<Col xs={24} md={12}>
<div>
<div style={{ marginBottom: 8, fontWeight: 500 }}>
间距 (gutter): {gutter}px
</div>
<Slider
min={0}
max={48}
step={4}
value={gutter}
onChange={setGutter}
marks={{
0: '0',
8: '8',
16: '16',
24: '24',
32: '32',
48: '48',
}}
/>
</div>
</Col>
<Col xs={24} md={8}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<span style={{ fontWeight: 500 }}>显示边框:</span>
<Switch checked={bordered} onChange={setBordered} />
</div>
</Col>
<Col xs={24} md={8}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<span style={{ fontWeight: 500 }}>幽灵模式:</span>
<Switch checked={ghost} onChange={setGhost} />
</div>
</Col>
<Col xs={24} md={8}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<span style={{ fontWeight: 500 }}>边框:</span>
<Segmented
value={bordered ? 'bordered' : 'borderless'}
onChange={(v) => setBordered(v === 'bordered')}
options={[
{ label: '有边框', value: 'bordered' },
{ label: '无边框', value: 'borderless' },
]}
/>
</div>
</Col>
</Row>
<Alert
title="代码示例"
description={
<pre style={{ margin: 0, fontSize: 12 }}>
{`<ProList
grid={{ gutter: ${gutter}, column: ${column} }}
itemCardProps={{ bordered: ${bordered}, ghost: ${ghost} }}
...
/>`}
</pre>
}
type="success"
style={{ marginTop: 24 }}
/>
</Card>
<ProList<any>
grid={{ gutter, column }}
itemCardProps={{
bordered,
ghost,
}}
ghost={ghost}
pagination={{
defaultPageSize: 12,
showSizeChanger: true,
pageSizeOptions: ['6', '12', '18', '24'],
}}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{ dataIndex: 'subTitle', listSlot: 'subTitle' },
{ dataIndex: 'avatar', listSlot: 'avatar' },
{ dataIndex: 'content', listSlot: 'content' },
{ dataIndex: 'actions', listSlot: 'actions' },
]}
headerTitle="Grid 布局示例"
tooltip="使用 CSS Grid 实现的响应式卡片布局"
dataSource={data}
/>
</div>
);
};
#表格/列表一键切换
同一份 columns 同时传给 ProTable 和 ProList,通过切换组件即可在表格和列表视图之间无缝切换。
/**
* 同一份 columns 同时用于 ProTable 和 ProList,一键切换视图
*/
import type { ProColumns } from '@ant-design/pro-components';
import { ProList, ProTable } from '@ant-design/pro-components';
import { Radio, Space, Tag } from 'antd';
import { useState } from 'react';
type DataItem = {
id: string;
name: string;
avatar: string;
status: 'open' | 'closed' | 'processing';
labels: string[];
updatedAt: string;
};
const dataSource: DataItem[] = [
{
id: '1',
name: '智慧零售平台',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
status: 'open',
labels: ['技术专栏', '设计语言'],
updatedAt: '2024-01-15',
},
{
id: '2',
name: 'Ant Design',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
status: 'processing',
labels: ['Ant Design'],
updatedAt: '2024-02-20',
},
{
id: '3',
name: '云原生微服务框架',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
status: 'closed',
labels: ['云原生', '可视化'],
updatedAt: '2024-03-10',
},
];
/**
* 这份 columns 同时用于 ProTable 和 ProList
* - ProTable 渲染为表格列
* - ProList 通过 listSlot 映射到列表项各部分
*/
const columns: ProColumns<DataItem>[] = [
{
title: '名称',
dataIndex: 'name',
listSlot: 'title',
},
{
title: '头像',
dataIndex: 'avatar',
listSlot: 'avatar',
search: false,
hideInTable: true,
},
{
title: '标签',
dataIndex: 'labels',
listSlot: 'subTitle',
search: false,
render: (_, row) => (
<Space size={4}>
{row.labels?.map((label) => (
<Tag color="blue" key={label}>
{label}
</Tag>
))}
</Space>
),
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: {
open: { text: '未解决', status: 'Error' },
closed: { text: '已解决', status: 'Success' },
processing: { text: '处理中', status: 'Processing' },
},
},
{
title: '更新时间',
dataIndex: 'updatedAt',
valueType: 'date',
search: false,
listSlot: 'description',
},
{
title: '操作',
listSlot: 'actions',
search: false,
render: () => [<a key="edit">编辑</a>, <a key="delete">删除</a>],
},
];
export default () => {
const [viewMode, setViewMode] = useState<'list' | 'table'>('list');
return (
<div style={{ padding: 24 }}>
<Radio.Group
value={viewMode}
onChange={(e) => setViewMode(e.target.value)}
style={{ marginBottom: 16 }}
optionType="button"
buttonStyle="solid"
options={[
{ label: '列表视图', value: 'list' },
{ label: '表格视图', value: 'table' },
]}
/>
{viewMode === 'list' ? (
<ProList<DataItem>
rowKey="id"
headerTitle="列表视图"
columns={columns}
dataSource={dataSource}
/>
) : (
<ProTable<DataItem>
rowKey="id"
headerTitle="表格视图"
columns={columns}
dataSource={dataSource}
search={false}
pagination={false}
/>
)}
</div>
);
};
#搜索列表(columns + request)
- 第 0-0 条/总共 0 条
- 1
/**
* columns API 配合 request 和搜索表单
*/
import type { ProColumns } from '@ant-design/pro-components';
import { ProList } from '@ant-design/pro-components';
import { Button, Space, Tag } from 'antd';
import request from 'umi-request';
type GithubIssueItem = {
url: string;
id: number;
number: number;
title: string;
labels: {
name: string;
color: string;
}[];
state: string;
comments: number;
created_at: string;
updated_at: string;
closed_at?: string;
};
const columns: ProColumns<GithubIssueItem>[] = [
{
title: '用户',
dataIndex: 'user',
listSlot: 'title',
},
{
dataIndex: 'avatar',
listSlot: 'avatar',
search: false,
},
{
dataIndex: 'title',
listSlot: 'description',
search: false,
},
{
dataIndex: 'labels',
listSlot: 'subTitle',
search: false,
render: (_, row) => (
<Space size={8}>
{row.labels?.map((label: { name: string }) => (
<Tag color="blue" key={label.name}>
{label.name}
</Tag>
))}
</Space>
),
},
{
listSlot: 'actions',
search: false,
render: (_, row) => [
<a href={row.url} target="_blank" rel="noopener noreferrer" key="link">
链路
</a>,
<a href={row.url} target="_blank" rel="noopener noreferrer" key="view">
查看
</a>,
],
},
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
valueEnum: {
all: { text: '全部', status: 'Default' },
open: { text: '未解决', status: 'Error' },
closed: { text: '已解决', status: 'Success' },
},
},
];
const Demo = () => (
<ProList<GithubIssueItem>
toolBarRender={() => [
<Button key="add" type="primary">
新建
</Button>,
]}
search={{ filterType: 'light' }}
rowKey="id"
headerTitle="搜索列表(columns API)"
request={async (params = {} as Record<string, any>) =>
request<{ data: GithubIssueItem[] }>(
'https://proapi.azurewebsites.net/github/issues',
{ params },
)
}
pagination={{ pageSize: 5 }}
columns={columns}
/>
);
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#可编辑列表(columns)
/**
* columns API 配合可编辑列表
*/
import type { ProColumns } from '@ant-design/pro-components';
import { ProList } from '@ant-design/pro-components';
import { Space, Tag } from 'antd';
import { useState } from 'react';
const defaultData = [
{
id: '1',
name: '智慧零售平台',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的 描述',
},
{
id: '2',
name: 'Ant Design',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
{
id: '3',
name: '云原生微服务框架',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
];
type DataItem = (typeof defaultData)[number];
const columns: ProColumns<DataItem>[] = [
{
title: '名称',
dataIndex: 'name',
listSlot: 'title',
},
{
dataIndex: 'image',
listSlot: 'avatar',
editable: false,
},
{
title: '描述',
dataIndex: 'desc',
listSlot: 'description',
},
{
listSlot: 'subTitle',
search: false,
editable: false,
render: () => (
<Space size={8}>
<Tag color="blue">Ant Design</Tag>
<Tag color="#5BD8A6">可视化</Tag>
</Space>
),
},
{
listSlot: 'actions',
search: false,
render: (_, row, __, action) => [
<a
onClick={() => {
action?.startEditable(row.id);
}}
key="edit"
>
编辑
</a>,
],
},
];
const Demo = () => {
const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
return (
<ProList<DataItem>
rowKey="id"
headerTitle="可编辑列表(columns API)"
dataSource={dataSource}
editable={{
onSave: async (key, record, originRow) => {
console.log(key, record, originRow);
return true;
},
}}
onDataSourceChange={setDataSource}
columns={columns}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#编辑列表
import { ProList } from '@ant-design/pro-components';
import { Space, Tag } from 'antd';
import { useState } from 'react';
const defaultData = [
{
id: '1',
name: '智慧零售平台',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
{
id: '2',
name: 'Ant Design',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
{
id: '3',
name: '云原生微服务框架',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
{
id: '4',
name: '数据可视化引擎',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
];
type DataItem = (typeof defaultData)[number];
const Demo = () => {
const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
return (
<ProList<DataItem>
rowKey="id"
headerTitle="基础列表"
dataSource={dataSource}
editable={{
onSave: async (_key, _record, _originRow) => {
return true;
},
}}
onDataSourceChange={setDataSource}
columns={[
{ dataIndex: 'name', listSlot: 'title' },
{ dataIndex: 'image', listSlot: 'avatar', editable: false },
{ dataIndex: 'desc', listSlot: 'description' },
{
listSlot: 'subTitle',
render: () => (
<Space size={8}>
<Tag color="blue">Ant Design</Tag>
<Tag color="#5BD8A6">可视化</Tag>
</Space>
),
},
{
listSlot: 'actions',
render: (text, row, index, action) => [
<a
onClick={() => {
action?.startEditable(row.id);
}}
key="link"
>
编辑
</a>,
],
},
]}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#带工具栏的列表
import type { ActionType } from '@ant-design/pro-components';
import { ProList } from '@ant-design/pro-components';
import { Badge, Button } from 'antd';
import React, { useRef, useState } from 'react';
const dataSource = [
{
name: '实验名称1',
desc: '系统性的沉淀B端知识体系',
content: [
{
label: '模型数',
value: 2903,
},
{
label: '指标数',
value: 3720,
},
{
label: '实验状态',
value: '成功',
status: 'success',
},
],
},
{
name: '实验名称2',
desc: '系统性的沉淀B端知识体系',
content: [
{
label: '模型数',
value: 2904,
},
{
label: '指标数',
value: 3721,
},
{
label: '实验状态',
value: '成功',
status: 'success',
},
],
},
{
name: '实验名称3',
desc: '系统性的沉淀B端知识体系',
content: [
{
label: '模型数',
value: 2905,
},
{
label: '指标数',
value: 3722,
},
{
label: '实验状态',
value: '成功',
status: 'success',
},
],
},
];
const renderBadge = (count: number, active = false) => {
return (
<Badge
count={count}
style={{
marginBlockStart: -2,
marginInlineStart: 4,
color: active ? '#1890FF' : '#999',
backgroundColor: active ? '#E6F7FF' : '#eee',
}}
/>
);
};
const Demo = () => {
const [activeKey, setActiveKey] = useState<React.Key | undefined>('tab1');
const action = useRef<ActionType>();
return (
<ProList<any>
rowKey="name"
actionRef={action}
dataSource={dataSource}
editable={{}}
columns={[
{
dataIndex: 'name',
listSlot: 'title',
valueType: 'select',
fieldProps: {
showSearch: true,
placement: 'bottomRight',
options: [{ label: '实验名称1', value: '实验名称1' }],
},
},
{ dataIndex: 'desc', listSlot: 'description' },
{
dataIndex: 'content',
listSlot: 'content',
render: (text) => (
<div
key="label"
style={{ display: 'flex', justifyContent: 'space-around' }}
>
{(text as any[]).map((t) => (
<div key={t.label}>
<div>{t.label}</div>
<div>
{t.status === 'success' && (
<span
style={{
display: 'inline-block',
width: 8,
height: 8,
borderRadius: '50%',
backgroundColor: '#52c41a',
marginInlineEnd: 8,
}}
/>
)}
{t.value}
</div>
</div>
))}
</div>
),
},
{
listSlot: 'actions',
render: (text, row) => [
<a
key="edit"
onClick={() => action.current?.startEditable(row.name)}
>
编辑
</a>,
<a key="copy">复制</a>,
<a key="delete">删除</a>,
],
},
]}
toolbar={{
menu: {
activeKey,
items: [
{
key: 'tab1',
label: (
<span>全部实验室{renderBadge(99, activeKey === 'tab1')}</span>
),
},
{
key: 'tab2',
label: (
<span>
我创建的实验室{renderBadge(32, activeKey === 'tab2')}
</span>
),
},
],
onChange(key) {
setActiveKey(key);
},
},
search: {
onSearch: (value: string) => {
alert(value);
},
},
actions: [
<Button type="primary" key="primary">
新建实验
</Button>,
],
}}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#支持展开的列表
import { ProList } from '@ant-design/pro-components';
import { Button, Progress, Space, Tag } from 'antd';
import type { Key } from 'react';
import { useState } from 'react';
const dataSource = [
{
title: '智慧零售平台',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
{
title: 'Ant Design',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
{
title: '云原生微服务框架',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
{
title: '数据可视化引擎',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
];
const Demo = () => {
const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
return (
<ProList<{ title: string }>
rowKey="title"
headerTitle="支持展开的列表"
toolBarRender={() => {
return [
<Button key="3" type="primary">
新建
</Button>,
];
}}
expandable={{ expandedRowKeys, onExpandedRowsChange: setExpandedRowKeys }}
dataSource={dataSource}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{
listSlot: 'subTitle',
render: () => (
<Space size={8}>
<Tag color="blue">Ant Design</Tag>
<Tag color="#5BD8A6">可视化</Tag>
</Space>
),
},
{
listSlot: 'description',
render: () => '面向企业级中后台的设计解决方案',
},
{ dataIndex: 'avatar', listSlot: 'avatar' },
{
listSlot: 'content',
render: () => (
<div
style={{
minWidth: 200,
flex: 1,
display: 'flex',
justifyContent: 'flex-end',
}}
>
<div
style={{
width: '200px',
}}
>
<div>发布中</div>
<Progress percent={80} />
</div>
</div>
),
},
{
listSlot: 'actions',
render: () => <a key="invite">邀请</a>,
},
]}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#支持选中的列表
import { ProList } from '@ant-design/pro-components';
import { Button, Progress } from 'antd';
import type { Key } from 'react';
import { useState } from 'react';
const dataSource = [
{
title: '智慧零售平台',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
{
title: 'Ant Design',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
{
title: '云原生微服务框架',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
{
title: '数据可视化引擎',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
},
];
const Demo = () => {
const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
const rowSelection = {
selectedRowKeys,
onChange: (keys: Key[]) => setSelectedRowKeys(keys),
};
return (
<ProList<{ title: string }>
toolBarRender={() => {
return [
<Button key="3" type="primary">
新建
</Button>,
];
}}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{
listSlot: 'description',
render: () => '面向企业级中后台的设计解决方案',
},
{ dataIndex: 'avatar', listSlot: 'avatar' },
{
listSlot: 'content',
render: () => (
<div
style={{
width: '200px',
}}
>
<div>发布中</div>
<Progress percent={80} />
</div>
),
},
{
listSlot: 'actions',
render: () => [
<a key="init">邀请</a>,
<Button key="publish" type="text">
发布
</Button>,
],
},
]}
rowKey="title"
headerTitle="支持选中的列表"
rowSelection={rowSelection}
dataSource={dataSource}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#查询列表
- 第 0-0 条/总共 0 条
- 1
import { ProList } from '@ant-design/pro-components';
import { Button, Space, Tag } from 'antd';
import request from 'umi-request';
type GithubIssueItem = {
url: string;
id: number;
number: number;
title: string;
labels: {
name: string;
color: string;
}[];
state: string;
comments: number;
created_at: string;
updated_at: string;
closed_at?: string;
};
const Demo = () => (
<ProList<GithubIssueItem>
toolBarRender={() => {
return [
<Button key="3" type="primary">
新建
</Button>,
];
}}
search={{}}
rowKey="name"
headerTitle="基础列表"
request={async (params = {} as Record<string, any>) =>
request<{
data: GithubIssueItem[];
}>('https://proapi.azurewebsites.net/github/issues', {
params,
})
}
pagination={{
pageSize: 5,
}}
columns={[
{ dataIndex: 'user', listSlot: 'title', title: '用户' },
{ dataIndex: 'avatar', listSlot: 'avatar', search: false },
{ dataIndex: 'title', listSlot: 'description', search: false },
{
dataIndex: 'labels',
listSlot: 'subTitle',
search: false,
render: (_, row) => (
<Space size={0}>
{row.labels?.map((label: { name: string }) => (
<Tag color="blue" key={label.name}>
{label.name}
</Tag>
))}
</Space>
),
},
{
listSlot: 'actions',
search: false,
render: (text, row) => [
<a
href={row.url}
target="_blank"
rel="noopener noreferrer"
key="link"
>
详情
</a>,
<a
href={row.url}
target="_blank"
rel="noopener noreferrer"
key="view"
>
查看
</a>,
],
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: {
all: { text: '全部', status: 'Default' },
open: { text: '未解决', status: 'Error' },
closed: { text: '已解决', status: 'Success' },
processing: { text: '解决中', status: 'Processing' },
},
},
]}
/>
);
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#带筛选和异步请求的列表
- 第 0-0 条/总共 0 条
- 1
import { ProList } from '@ant-design/pro-components';
import { Button, Space, Tag } from 'antd';
import request from 'umi-request';
type GithubIssueItem = {
url: string;
id: number;
number: number;
title: string;
labels: {
name: string;
color: string;
}[];
state: string;
comments: number;
created_at: string;
updated_at: string;
closed_at?: string;
};
const Demo = () => (
<ProList<GithubIssueItem>
toolBarRender={() => {
return [
<Button key="3" type="primary">
新建
</Button>,
];
}}
search={{
filterType: 'light',
}}
rowKey="name"
headerTitle="基础列表"
request={async (params = {} as Record<string, any>) =>
request<{
data: GithubIssueItem[];
}>('https://proapi.azurewebsites.net/github/issues', {
params,
})
}
pagination={{
pageSize: 5,
}}
columns={[
{ dataIndex: 'user', listSlot: 'title', title: '用户' },
{ dataIndex: 'avatar', listSlot: 'avatar', search: false },
{ dataIndex: 'title', listSlot: 'description', search: false },
{
dataIndex: 'labels',
listSlot: 'subTitle',
search: false,
render: (_, row) => (
<Space size={8}>
{row.labels?.map((label: { name: string }) => (
<Tag color="blue" key={label.name}>
{label.name}
</Tag>
))}
</Space>
),
},
{
listSlot: 'actions',
search: false,
render: (text, row) => [
<a
href={row.url}
target="_blank"
rel="noopener noreferrer"
key="link"
>
详情
</a>,
<a
href={row.url}
target="_blank"
rel="noopener noreferrer"
key="view"
>
查看
</a>,
],
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: {
all: { text: '全部', status: 'Default' },
open: { text: '未解决', status: 'Error' },
closed: { text: '已解决', status: 'Success' },
processing: { text: '解决中', status: 'Processing' },
},
},
]}
/>
);
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#大小和分割线
import { ProList } from '@ant-design/pro-components';
import { Button, Progress, Select, Tag } from 'antd';
import type { Key } from 'react';
import { useState } from 'react';
type ProjectItem = {
title: string;
avatar: string;
description: string;
progress: number;
status: string;
};
const dataSource: ProjectItem[] = [
{
title: '智慧零售平台',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '面向线下门店的数字化经营解决方案',
progress: 85,
status: '开发中',
},
{
title: 'Ant Design Pro',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '开箱即用的中台前端解决方案',
progress: 100,
status: '已上线',
},
{
title: '云原生微服务框架',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '基于 K8s 的微服务开发与治理框架',
progress: 92,
status: '测试中',
},
{
title: '数据可视化引擎',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
description: '企业级数据看板与图表分析工具',
progress: 60,
status: '开发中',
},
];
const Demo = () => {
const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
const [size, setSize] = useState<'small' | 'default' | 'large' | undefined>(
'default',
);
const [split, setSplit] = useState<0 | 1>(1);
const rowSelection = {
selectedRowKeys,
onChange: (keys: Key[]) => setSelectedRowKeys(keys),
};
return (
<>
大小:
<Select<string>
value={size}
onChange={(value) => setSize(value as any)}
options={['small', 'default', 'large'].map((selectSize) => ({
value: selectSize,
label: selectSize,
}))}
/>{' '}
分割线:
<Select<0 | 1>
value={split}
onChange={(value) => setSplit(value)}
options={[
{ value: 1, label: '有' },
{ value: 0, label: '无' },
]}
/>{' '}
<br />
<br />
<ProList<ProjectItem>
size={size}
split={split === 1}
toolBarRender={() => {
return [
<Button key="new" type="primary">
新建
</Button>,
];
}}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{ dataIndex: 'description', listSlot: 'description' },
{ dataIndex: 'avatar', listSlot: 'avatar' },
{
listSlot: 'content',
render: (_, record) => (
<div
style={{
minWidth: 200,
flex: 1,
display: 'flex',
justifyContent: 'flex-end',
}}
>
<div style={{ width: 200 }}>
<div>
{record.status}{' '}
<Tag
color={record.progress === 100 ? 'success' : 'processing'}
>
{record.progress}%
</Tag>
</div>
<Progress percent={record.progress} showInfo={false} />
</div>
</div>
),
},
{
listSlot: 'actions',
render: () => [<a key="invite">邀请</a>],
},
]}
expandable={{
expandedRowKeys,
defaultExpandAllRows: false,
onExpandedRowsChange: setExpandedRowKeys,
}}
rowKey="title"
headerTitle="大小和分割线"
rowSelection={rowSelection}
dataSource={dataSource}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#竖排样式
智慧零售平台

Ant Design

云原生微服务框架

数据可视化引擎

import { LikeOutlined, MessageOutlined, StarOutlined } from '@ant-design/icons';
import { ProList } from '@ant-design/pro-components';
import { Button, Space, Tag } from 'antd';
import React from 'react';
const IconText = ({ icon, text }: { icon: any; text: string }) => (
<span>
{React.createElement(icon, { style: { marginInlineEnd: 8 } })}
{text}
</span>
);
const dataSource = [
{
title: '智慧零售平台',
},
{
title: 'Ant Design',
},
{
title: '云原生微服务框架',
},
{
title: '数据可视化引擎',
},
];
const Demo = () => {
return (
<ProList<{ title: string }>
toolBarRender={() => {
return [
<Button key="3" type="primary">
新建
</Button>,
];
}}
itemLayout="vertical"
rowKey="id"
headerTitle="竖排样式"
dataSource={dataSource}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{
listSlot: 'description',
render: () => (
<Space orientation="horizontal">
<Tag>技术专栏</Tag>
<Tag>设计语言</Tag>
<Tag>云原生</Tag>
</Space>
),
},
{
listSlot: 'actions',
render: () => [
<IconText icon={StarOutlined} text="156" key="star" />,
<IconText icon={LikeOutlined} text="156" key="like" />,
<IconText icon={MessageOutlined} text="2" key="message" />,
],
},
{
listSlot: 'aside',
render: () => (
<img
width={272}
alt="logo"
src="https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png"
/>
),
},
{
listSlot: 'content',
render: () => (
<div>
面向企业级中后台的数据可视化解决方案,以最小的接入成本提供丰富的图表类型与交互能力,助力业务快速搭建数据看板与分析报表。
</div>
),
},
]}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#一些预设的模式
import { EllipsisOutlined } from '@ant-design/icons';
import { ProList } from '@ant-design/pro-components';
import { Button, Progress, Tag } from 'antd';
import React, { Key, useState } from 'react';
const types = ['top', 'inline', 'new'];
const data = [
'智慧零售平台(top)',
'Ant Design Pro(inline)',
'云原生微服务框架(new)',
'数据可视化引擎',
].map((item, index) => ({
title: item,
subTitle: <Tag color="#5BD8A6">技术专栏</Tag>,
actions: [
<a key="invite">邀请</a>,
<a key="operate">操作</a>,
<a key="rest">
<EllipsisOutlined />
</a>,
],
description: (
<div>
<div>top 会有小角标</div>
<div>inline 标题字体是 normal</div>
<div>new 会有一个入场动画</div>
</div>
),
type: types[index],
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
content: (
<div
style={{
flex: 1,
display: 'flex',
justifyContent: 'flex-end',
}}
>
<div
style={{
width: 200,
}}
>
<div>发布中</div>
<Progress percent={80} />
</div>
</div>
),
}));
const Demo = () => {
const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
const rowSelection = {
selectedRowKeys,
onChange: (keys: Key[]) => setSelectedRowKeys(keys),
};
const [dataSource, setDataSource] = useState<any[]>([...data] as any[]);
return (
<>
<ProList<{
title: string;
subTitle: React.JSX.Element;
actions: React.JSX.Element[];
description: React.JSX.Element;
type?: 'top' | 'inline' | 'new';
avatar: string;
children: React.JSX.Element;
}>
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{ dataIndex: 'subTitle', listSlot: 'subTitle' },
{ dataIndex: 'type', listSlot: 'type' },
{ dataIndex: 'description', listSlot: 'description' },
{ dataIndex: 'avatar', listSlot: 'avatar' },
{ dataIndex: 'content', listSlot: 'content' },
{ dataIndex: 'actions', listSlot: 'actions' },
]}
toolBarRender={() => [
<Button
key="3"
type="primary"
onClick={() => {
setDataSource([...data.map((item) => ({ ...item }))]);
setTimeout(() => {
const list = [...data.map((item) => ({ ...item }))];
list[1].type = 'new';
setDataSource(list);
}, 0);
}}
>
刷新
</Button>,
]}
rowKey="id"
headerTitle="预设的列状态"
rowSelection={rowSelection}
dataSource={dataSource}
expandable={{
expandedRowKeys,
onExpandedRowsChange: setExpandedRowKeys,
}}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#翻页
import { EllipsisOutlined } from '@ant-design/icons';
import { ProList } from '@ant-design/pro-components';
import { Progress, Tag } from 'antd';
const data = [
'智慧零售平台',
'Ant Design Pro',
'云原生微服务框架',
'数据可视化引擎',
'智能客服系统',
'DevOps 工具链',
'统一权限管理中心',
].map((item) => ({
title: item,
subTitle: <Tag color="#5BD8A6">技术专栏</Tag>,
actions: [
<a key="invite">邀请</a>,
<a key="operate">操作</a>,
<a key="rest">
<EllipsisOutlined />
</a>,
],
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
content: (
<div
style={{
flex: 1,
display: 'flex',
justifyContent: 'flex-end',
}}
>
<div
style={{
width: 200,
}}
>
<div>发布中</div>
<Progress percent={80} />
</div>
</div>
),
}));
const Demo = () => {
return (
<ProList<any>
pagination={{
defaultPageSize: 5,
showSizeChanger: true,
}}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{ dataIndex: 'subTitle', listSlot: 'subTitle' },
{ dataIndex: 'type', listSlot: 'type' },
{ dataIndex: 'avatar', listSlot: 'avatar' },
{ dataIndex: 'content', listSlot: 'content' },
{ dataIndex: 'actions', listSlot: 'actions' },
]}
headerTitle="翻页"
dataSource={data}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#自定义列表项(itemRender)
通过 itemRender 自定义每一项的渲染,可基于默认内容 defaultDom(React.ReactElement)进行包装或完全自定义。
import { ProList } from '@ant-design/pro-components';
import { Avatar, theme } from 'antd';
const APPLICATIONS = [
{
id: '1',
title: '帆软 SSO',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
description:
'FineReport 是一款用于报表制作、分析和展示的软件,支持数据填报与可视化大屏。',
},
{
id: '2',
title: '泛微 E9 SSO',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
description:
'泛微 E9 是一款成熟的协同办公软件,以流程管理、知识管理为核心。',
},
{
id: '3',
title: '销售易',
avatar:
'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
description:
'SAML (Security Assertion Markup Language) 是一种用于身份认证与授权的标准协议。',
},
];
type AppItem = (typeof APPLICATIONS)[0];
export default () => {
const { token } = theme.useToken();
return (
<div
style={{
backgroundColor: token.colorBgLayout,
margin: -24,
padding: 64,
}}
>
<ProList<AppItem>
rowKey="id"
split
grid={{
xs: 1,
sm: 2,
md: 2,
lg: 4,
xl: 4,
xxl: 4,
gutter: [16, 16],
}}
pagination={false}
columns={[
{ dataIndex: 'title', listSlot: 'title' },
{ dataIndex: 'avatar', listSlot: 'avatar' },
{ dataIndex: 'description', listSlot: 'description' },
]}
dataSource={APPLICATIONS}
toolbar={{
menu: {
type: 'tab',
items: [
{ key: 'all', label: '全部应用' },
{ key: 'dev', label: '开发类' },
{ key: 'ops', label: '运维类' },
{ key: 'office', label: '办公类' },
],
},
}}
itemRender={(item) => (
<div
style={{
width: '100%',
minWidth: 0,
boxSizing: 'border-box',
borderRadius: 8,
padding: 24,
height: '100%',
cursor: 'pointer',
boxShadow: '0 1px 2px rgba(0,0,0,0.03)',
background: token.colorBgContainer,
}}
tabIndex={0}
>
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
<Avatar
src={item.avatar}
shape="square"
size={48}
style={{ flexShrink: 0 }}
/>
<div style={{ flex: 1, minWidth: 0 }}>
<div
style={{
fontWeight: 600,
fontSize: 16,
marginBottom: 4,
}}
>
{item.title}
</div>
<div
style={{
color: token.colorTextSecondary,
fontSize: 14,
lineHeight: 1.5,
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
}}
>
{item.description}
</div>
</div>
</div>
</div>
)}
/>
</div>
);
};
#API
ProList 基于 ProTable 封装,支持两种列配置方式:
columns+listSlot(推荐):与 ProTable 共用相同的columns数组,通过listSlot指定每列映射到列表项的哪个插槽位置。同一份columns可同时用于 ProTable 和 ProList,便于在表格和列表之间切换。metas(已废弃):旧的配置方式,使用对象的键名来映射列表项的各个部分。仍可正常使用,但推荐迁移到columns+listSlot。
其余 API 与 ProTable 相同。
#request
request 是 ProList 最重要的 API,与 ProTable 用法一致。request 会接收一个对象,对象中必须要有 data 和 success,如果需要手动分页 total 也是必需的。request 会接管 loading 的设置,同时在查询表单查询时和 params 参数发生修改时重新执行。
<ProList<DataType, Params>
params={params}
request={async (params, sort, filter) => {
const msg = await myQuery({
page: params.current,
pageSize: params.pageSize,
});
return {
data: msg.result,
success: true,
total: msg.total,
};
}}
/>#ProList
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| columns | 列配置,与 ProTable 相同,通过 listSlot 指定列表项插槽,详见 columns 配置 | ProColumns<T>[] | - |
| metas | columns + listSlot | Metas | - |
| dataSource | 与 antd 相同的配置,ProList 推荐使用 request 来加载 | T[] | - |
| request | 获取 dataSource 的方法 | (params: U & { pageSize?: number; current?: number; keyword?: string }, sort: Record<string, SortOrder>, filter: Record<string, FilterValue>) => Promise<{ data: T[]; success?: boolean; total?: number }> | - |
| params | 用于 request 查询的额外参数,一旦变化会触发重新加载 | U | - |
| postData | 对通过 request 获取的数据进行处理 | (data: T[]) => T[] | - |
| defaultData | 默认的数据 | T[] | - |
| onDataSourceChange | 数据发生改变时触发 | (dataSource: T[]) => void | - |
| actionRef | Table action 的引用,便于自定义触发 | React.Ref<ActionType | undefined> | - |
| formRef | 可以获取到查询表单的 form 实例,用于一些灵活的配置 | TableFormItem<T>['formRef'] | - |
| rowKey | 行的 key,一般是行 id,未设置时依次尝试 item.key、行索引 | keyof T | (item: T) => React.Key | - |
| headerTitle | 左上角的 title | ReactNode | - |
| tooltip | 标题旁边的 tooltip | string | LabelTooltipType | - |
| loading | 是否加载中 | boolean | { spinning?: boolean } | false |
| split | 是否有分割线 | boolean | true |
| variant | 列表外观变体 | 'outlined' | 'borderless' | 'filled' | 'borderless' |
| showActions | 何时展示 操作区(actions),'hover' 时悬浮或聚焦列表项才显示 | 'hover' | 'always' | 'always' |
| showExtra | 何时展示附属内容(aside 插槽映射的 extra 区域),'hover' 时悬浮列表项才显示,CardList 模式下不生效 | 'hover' | 'always' | 'always' |
| footer | 列表底部 | ReactNode | - |
| grid | 栅格配置,开启后以卡片模式渲染 | ListGridType | - |
| itemLayout | 列表项布局方向 | 'horizontal' | 'vertical' | 'horizontal' |
| locale | 国际化配置 | { emptyText?: ReactNode } | - |
| pagination | 分页器的配置,current 和 pageSize 会被 request 接管 | PaginationConfig | false | false |
| rowSelection | 选择项配置 | TableProps<T>['rowSelection'] & { alwaysShowAlert?: boolean } | false | false |
| expandable | 与 antd 相同的配置 | object | false | - |
| onRow | 与 antd 相同的配置,用户传入 grid 属性时列表以卡片模式渲染,此事件不触发,请使用 onItem | function(record, index) | - |
| onItem | 与 antd 相同的配置,在所有类型点击某个项目都会触发该事件 | function(record, index) | - |
| itemRender | 自定义列表项渲染,defaultDom 为默认列表项元素,可基于其包装或完全自定义 | (item: T, index: number, defaultDom: React.ReactElement) => ReactNode | - |
| rowClassName | 自定义列表行的类名 | string | (item: T, index: number) => string | - |
| itemHeaderRender | 自定义每一列的 header,与 itemRender 不同的是,它会保留多选和展开收起 | ((item: T, index: number, defaultDom: JSX.Element | null) => ReactNode) | false | - |
| itemTitleRender | 自定义每一列的 title 渲染 | ((item: T, index: number, defaultDom: JSX.Element | null) => ReactNode) | false | - |
| itemCardProps | 自定义卡片列表的 props,只在卡片列表下生效 | CheckCardProps | - |
| toolBarRender | 渲染工具栏,支持返回一个 dom 数组,会自动增加 margin-right | ToolBarProps<T>['toolBarRender'] | false | - |
| search | 是否显示搜索表单,传入对象时为搜索表单的配置 | false | SearchConfig | false |
| onLoad | 数据加载完成后触发,会多次触发 | (dataSource: T[]) => void | - |
| onLoadingChange | loading 被修改时触发,一般是网 络请求导致的 | (loading: boolean | SpinProps | undefined) => void | - |
| onRequestError | 数据加载失败时触发 | (error: Error) => void | - |
| onSubmit | 提交表单时触发 | (params: U) => void | - |
| onReset | 重置表单时触发 | () => void | - |
| cardProps | 外面卡片的设置 | ProCardProps | false | - |
| editable | 可编辑列表的相关配置,详见 可编辑表格 | RowEditableConfig<T> | - |
| manualRequest | 是否需要手动触发首次请求 | boolean | false |
| ghost | 幽灵模式,即是否取消区域的 padding | boolean | false |
| dateFormatter | 转化 dayjs 格式数据为特定类型,false 不做转化 | "string" | "number" | ((value: dayjs.Dayjs, valueType: string) => string | number) | false | "string" |
| ErrorBoundary | 自带了错误处理功能,防止白屏,ErrorBoundary=false 关闭默认错误边界 | React.ComponentClass<any, any> | false | 内置 ErrorBoundary |
#ActionRef 手动触发
有时我们要手动触发 ProList 的 reload 等操作,可以使用 actionRef,用法与 ProTable ActionRef 完全一致。
| 方法 | 描述 | 类型 |
|---|---|---|
| reload | 刷新列表,如果传入 true 则重置页码 | (resetPageIndex?: boolean) => Promise<void> |
| reloadAndRest | 刷新并清空,页码也会重置,不包括表单 | () => Promise<void> |
| reset | 重置到默认值,包括表单 | () => void |
| clearSelected | 清空选中项 | () => void |
| startEditable | 开始编辑行 | (rowKey: Key) => boolean |
| cancelEditable | 取消编辑行 | (rowKey: Key) => boolean |
const ref = useRef<ActionType>();
<ProList actionRef={ref} />;
// 刷新
ref.current?.reload();
// 刷新并清空,页码也会重置,不包括表单
ref.current?.reloadAndRest();
// 重置到默认值,包括表单
ref.current?.reset();
// 清空选中项
ref.current?.clearSelected();#columns 配置(推荐)
同一份 columns 可以同时用于 ProTable(表格视图)和 ProList(列表视图),ProTable 会忽略 listSlot 属性,ProList 使用 listSlot 将数据映射到列表项的各个插槽位置。没有 listSlot 的列不会渲染到列表项中,但仍会参与搜索表单的生成。
#ProList 扩展的列属性
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| listSlot | 指定该列映射到列表项的哪个插槽位置 | 'title' | 'subTitle' | 'avatar' | 'description' | 'content' | 'actions' | 'aside' | 'type' | - |
其余列属性与 ProTable 的 ProColumns 完全一致(dataIndex、valueType、render、search、valueEnum 等),详见 ProTable columns。
#listSlot 插槽说明
| 插槽值 | 说明 | 默认 valueType |
|---|---|---|
title | 列表项标题 | text |
subTitle | 列表项副标题 | text |
avatar | 列表项头像 | avatar |
description | 列表项描述 | textarea |
content | 列表项内容区域 | text |
actions | 列表项操作区 | option |
aside | 列表项附属内容,通常展示在右侧(如图片、进度条等非交互内容) | text |
type | 列表项类型('new' | 'top' | 'inline') | text |
#使用示例
import type { ProColumns } from '@ant-design/pro-components';
// 同一份 columns 可同时用于 ProTable 和 ProList
const columns: ProColumns<DataItem>[] = [
{ title: '名称', dataIndex: 'name', listSlot: 'title' },
{ dataIndex: 'avatar', listSlot: 'avatar', search: false },
{ dataIndex: 'desc', listSlot: 'description', search: false },
{
title: '标签',
dataIndex: 'labels',
listSlot: 'subTitle',
search: false,
render: (_, row) => <Tag>{row.label}</Tag>,
},
{
title: '操作',
listSlot: 'actions',
search: false,
render: (_, row) => [<a key="edit">编辑</a>],
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: { open: { text: '未解决' }, closed: { text: '已解决' } },
// 没有 listSlot,不渲染到列表 项中,仅用于搜索
},
];
<ProList columns={columns} /> // 列表视图
<ProTable columns={columns} /> // 表格视图#Metas 配置(已废弃)
已废弃:
metas仍可正常使用,但推荐迁移到columns+listSlot。详见下方从 metas 迁移到 columns 指引。
Metas 使用对象的键名来映射列表项各个部分(标题、头像、描述等)对应的数据字段。
#Metas.[Meta] 通用 API
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | 数据在数据项中对应的路径,支持通过数组查询嵌套路径 | string | string[] | - |
| title | 标题 | ReactNode | - |
| valueType | 值的类型,和 ProTable 一致,会生成不同的渲染器 | valueType | 'text' |
| render | 自定义渲染函数 | (text: ReactNode, record: T, index: number) => ReactNode | ReactNode[] | - |
| valueEnum | 值的枚举,会自动转化把值当成 key 来取出要显示的内容 | valueEnum | - |
| search | 配置列的搜索相关,false 为隐藏 | boolean | { transform: (value: any) => any } | - |
| editable | 在编辑列表中是否可编辑 | boolean | (text: any, record: T, index: number) => boolean | - |
| fieldProps | 查询表单的 props,会透传给表单项 | (form, config) => Record | Record | - |
| formItemProps | 传递给 Form.Item 的配置 | (form, config) => formItemProps | formItemProps | - |
| formItemRender | 渲染查询表单的输入组件 | (item, { type, defaultRender, formItemProps, fieldProps, ...rest }, form) => ReactNode | - |
| key | React 的 key | React.Key | - |
#Metas.type
对应 dataSource 的字段类型为 'new' | 'top' | 'inline'。
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | - | - | 'type' |
#Metas.title
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | - | - | 'title' |
#Metas.subTitle
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | - | - | 'subTitle' |
#Metas.description
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | - | - | 'description' |
#Metas.avatar
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | - | - | 'avatar' |
#Metas.actions
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | - | - | 'actions' |
#Metas.content
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| dataIndex | - | - | 'content' |
metas中仅支持type、title、subTitle、description、avatar、content、actions这些键。旧文档中的Metas.extra并不存在于类型定义中,右侧附属内容请使用columns的listSlot: 'aside'(内部映射到列表项的extra区域)。
#批量操作
与 ProTable 相同,批量操作需要设置 rowSelection 来开启。详见 ProTable 批量操作。
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| alwaysShowAlert | 总是展示 alert,默认无选择不展示(rowSelection 内置属性) | boolean | - |
| tableAlertRender | 自定义批量操作工具栏左侧信息区域,false 时不显示 | ({ selectedRowKeys: Key[], selectedRows: T[], onCleanSelected: () => void }) => ReactNode) | false | - |
| tableAlertOptionRender | 自定义批量操作工具栏右侧选项区域,false 时不显示 | ({ selectedRowKeys: Key[], selectedRows: T[], onCleanSelected: () => void }) => ReactNode) | false | - |
#搜索表单
ProList 会根据 columns 或 metas 中配置了 search 的字段来生成搜索表单,用法与 ProTable 搜索表单 一致。
#从 metas 迁移到 columns
metas 已废弃,推荐迁移到 columns + listSlot。迁移规则非常简单:将 metas 对象的每个键值对转换为 columns 数组中的一个元素,键名对应 listSlot,值的属性直接展开到列配置中。
#迁移对照表
| metas 写法 | columns 写法 |
|---|---|
title: { dataIndex: 'name' } | { dataIndex: 'name', listSlot: 'title' } |
avatar: { dataIndex: 'img' } | { dataIndex: 'img', listSlot: 'avatar' } |
description: { dataIndex: 'desc' } | { dataIndex: 'desc', listSlot: 'description' } |
content: {} | { dataIndex: 'content', listSlot: 'content' } |
extra: { render: ... } | { listSlot: 'aside', render: ... } |
status: { title: '状态', valueType: 'select', ... } | { title: '状态', dataIndex: 'status', valueType: 'select', ... } |
#完整示例
迁移前(metas):
<ProList
metas={{
title: { dataIndex: 'name', title: '名称' },
avatar: { dataIndex: 'avatar', search: false },
description: { dataIndex: 'desc', search: false },
subTitle: {
dataIndex: 'labels',
render: (_, row) => <Tag>{row.label}</Tag>,
search: false,
},
actions: {
render: (_, row) => [<a key="edit">编辑</a>],
search: false,
},
status: {
title: '状态',
valueType: 'select',
valueEnum: { open: { text: '未解决' }, closed: { text: '已解决' } },
},
}}
/>迁移后(columns + listSlot):
<ProList
columns={[
{ title: '名称', dataIndex: 'name', listSlot: 'title' },
{ dataIndex: 'avatar', listSlot: 'avatar', search: false },
{ dataIndex: 'desc', listSlot: 'description', search: false },
{
dataIndex: 'labels',
listSlot: 'subTitle',
render: (_, row) => <Tag>{row.label}</Tag>,
search: false,
},
{
listSlot: 'actions',
render: (_, row) => [<a key="edit">编辑</a>],
search: false,
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: { open: { text: '未解决' }, closed: { text: '已解决' } },
},
]}
/>提示:迁移后的
columns可以直接传给ProTable使用,实现列表和表格视图的一键切换。


