#ProField
该组件为内部组件,请勿直接使用。
原子信息组件,统一 ProForm、ProTable、ProList、Filter 等组件里面的字段定义。
#DEMO
#Issue 回归场景
字段回归场景
覆盖对象形式 showSearch、受控 TreeSelect、只读空值、数字前后缀及混合 valueEnum。
SearchSelect 回调与远程请求(#9711)
输入关键字时,自定义 onSearch 与 request 会同时收到关键字。
onSearch: (尚未搜索)字段数据流与只读展示(B7–B10)
搜索、数据流与只读展示
import {
ProCard,
ProForm,
ProFormDigit,
ProFormSelect,
ProFormTreeSelect,
} from '@ant-design/pro-components';
import { Alert, Space, Typography } from 'antd';
import { useState } from 'react';
const remoteOptions = ['Alpha', 'Beta', 'Gamma', 'Delta'];
export default () => {
const [lastSearch, setLastSearch] = useState('(尚未搜索)');
const [treeOpen, setTreeOpen] = useState(false);
return (
<ProCard direction="column" ghost gutter={[0, 16]}>
<Alert
type="info"
showIcon
message="字段回归场景"
description="覆盖对象形式 showSearch、受控 TreeSelect、只读空值、数字前后缀及混合 valueEnum。"
/>
<ProCard title="SearchSelect 回调与远程请求(#9711)">
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
输入关键字时,自定义 onSearch 与 request 会同时收到关键字。
</Typography.Text>
<ProForm submitter={false}>
<ProFormSelect.SearchSelect
name="keyword"
label="远程搜索"
debounceTime={100}
request={async ({ keyWords }) => {
const keyword = keyWords ?? '';
return remoteOptions
.filter((item) =>
item.toLowerCase().includes(keyword.toLowerCase()),
)
.map((item) => ({ label: item, value: item }));
}}
fieldProps={{
showSearch: {
onSearch: (value) => setLastSearch(value || '(空)'),
},
}}
/>
</ProForm>
<Typography.Text code>onSearch: {lastSearch}</Typography.Text>
</Space>
</ProCard>
<ProCard title="字段数据流与只读展示(B7–B10)">
<ProForm
submitter={false}
initialValues={{ amount: 128, status: 0, category: 'frontend' }}
layout="horizontal"
>
<ProFormDigit
name="amount"
label="带前后缀数字"
fieldProps={{ prefix: '¥', addonAfter: '元' }}
/>
<ProFormSelect
name="status"
label="混合值 valueEnum"
valueEnum={
new Map<string | number, React.ReactNode>([
[0, '未开始'],
['1', '进行中'],
[2, '已完成'],
])
}
/>
<ProFormTreeSelect
name="category"
label="受控 TreeSelect"
fieldProps={{
open: treeOpen,
onOpenChange: setTreeOpen,
treeData: [
{
title: '研发',
value: 'development',
children: [
{ title: '前端', value: 'frontend' },
{ title: '后端', value: 'backend' },
],
},
],
}}
/>
<ProFormDigit
label="只读空值"
name="empty"
readonly
fieldProps={{ addonAfter: '次' }}
/>
</ProForm>
</ProCard>
</ProCard>
);
};
模式:
文本与展示类
数值类
金额 money¥128,000.00 | 数字 digit1,234,567 |
数字范围 digitRange1,000 ~ 5,000 | 秒格式化 second1天0秒 |
百分比 percent99.50% | 百分比(带颜色) + 15.00% 0.00% - 8.00% |
进度条 progress 75% | 评分 rate |
滑动条 slider60 | |
枚举选择类
选择框 select待处理 | 单选 radio待处理 |
单选按钮 radioButton待处理 | 多选 checkbox 待处理 ,进行中 |
开关 switch打开 | 分段选择 segmented待处理 |
远程选择框 select(request)open | 级联选择 cascader zhejiang ,hangzhou ,xihu |
树形选择 treeSelect前端开发组 | 颜色选择 color |
日期时间类
日期 date2024-01-15 | 日期时间 dateTime2024-01-15 10:30:00 |
周 dateWeek2024-3rd | 月 dateMonth2024-01 |
季度 dateQuarter2024-Q1 | 年 dateYear2024 |
时间 time10:30:00 | 相对时间 fromNow3 years ago |
日期范围类
日期范围 dateRange 2024-01-01 ~ 2024-01-31 | 日期时间范围 dateTimeRange 2024-01-01 09:00:00 ~ 2024-01-31 18:00:00 |
时间范围 timeRange 09:00:00 ~ 18:00:00 | 周范围 dateWeekRange 2024-1st ~ 2024-3rd |
月范围 dateMonthRange 2024-01 ~ 2024-06 | 季度范围 dateQuarterRange 2024-Q1 ~ 2024-Q3 |
年范围 dateYearRange 2023 ~ 2025 | |
代码类
代码块 code | JSON 代码块 jsonCode |
import type { ProFieldFCMode } from '@ant-design/pro-components';
import { ProField } from '@ant-design/pro-components';
import { Descriptions, Segmented, Space } from 'antd';
import dayjs from 'dayjs';
import React, { useState } from 'react';
const DEMO_TIMESTAMP = dayjs('2024-01-15 10:30:00').valueOf();
const statusEnum = {
all: { text: '全部', disabled: true, status: 'Default' },
open: { text: '待处理', status: 'Error' },
closed: { text: '已完成', status: 'Success' },
processing: { text: '进行中', status: 'Processing' },
};
/** 受控 ProField,同时传 text + value 确保 read/edit 模式都有值 */
const DemoField: React.FC<{
initialValue: any;
mode: ProFieldFCMode;
valueType?: any;
[key: string]: any;
}> = ({ initialValue, mode, ...rest }) => {
const [val, setVal] = useState(initialValue);
return (
<ProField text={val} value={val} onChange={setVal} mode={mode} {...rest} />
);
};
const Demo = () => {
const [state, setState] = useState<ProFieldFCMode>('read');
return (
<div
style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 24 }}
>
<div style={{ marginBlockEnd: 16 }}>
<span>模式:</span>
<Segmented
value={state}
onChange={(v) => setState(v as ProFieldFCMode)}
options={[
{ label: '只读 read', value: 'read' },
{ label: '编辑 edit', value: 'edit' },
]}
/>
</div>
<Descriptions column={2} title="文本与展示类">
<Descriptions.Item label="空字符串">
<ProField text="" mode="read" />
</Descriptions.Item>
<Descriptions.Item label="文本 text">
<DemoField
initialValue="用户认证服务"
valueType="text"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="文本域 textarea">
<DemoField
initialValue="核心服务,承载全站用户登录与鉴权,高峰期需要关注性能指标"
valueType="textarea"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="密码 password">
<DemoField
initialValue="pro-components"
valueType="password"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="头像 avatar">
<ProField
text="https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg"
mode="read"
valueType="avatar"
/>
</Descriptions.Item>
<Descriptions.Item label="图片 image">
<DemoField
initialValue="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
valueType="image"
mode={state}
/>
</Descriptions.Item>
</Descriptions>
<Descriptions column={2} title="数值类">
<Descriptions.Item label="金额 money">
<DemoField initialValue={128000} valueType="money" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="数字 digit">
<DemoField initialValue={1234567} valueType="digit" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="数字范围 digitRange">
<DemoField
initialValue={[1000, 5000]}
valueType="digitRange"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="秒格式化 second">
<DemoField initialValue={86400} valueType="second" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="百分比 percent">
<DemoField initialValue={99.5} valueType="percent" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="百分比(带颜色)">
<Space>
<ProField
text={15}
valueType={{ type: 'percent', showSymbol: true, showColor: true }}
mode="read"
/>
<ProField
text={0}
valueType={{ type: 'percent', showSymbol: true, showColor: true }}
mode="read"
/>
<ProField
text={-8}
valueType={{ type: 'percent', showSymbol: true, showColor: true }}
mode="read"
/>
</Space>
</Descriptions.Item>
<Descriptions.Item label="进度条 progress">
<DemoField initialValue={75} valueType="progress" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="评分 rate">
<DemoField initialValue={4} valueType="rate" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="滑动条 slider">
<DemoField initialValue={60} valueType="slider" mode={state} />
</Descriptions.Item>
</Descriptions>
<Descriptions column={2} title="枚举选择类">
<Descriptions.Item label="选择框 select">
<DemoField initialValue="open" mode={state} valueEnum={statusEnum} />
</Descriptions.Item>
<Descriptions.Item label="单选 radio">
<DemoField
initialValue="open"
mode={state}
valueType="radio"
valueEnum={statusEnum}
/>
</Descriptions.Item>
<Descriptions.Item label="单选按钮 radioButton">
<DemoField
initialValue="open"
mode={state}
valueType="radioButton"
valueEnum={statusEnum}
/>
</Descriptions.Item>
<Descriptions.Item label="多选 checkbox">
<DemoField
initialValue={['open', 'processing']}
mode={state}
valueType="checkbox"
valueEnum={statusEnum}
/>
</Descriptions.Item>
<Descriptions.Item label="开关 switch">
<DemoField initialValue={true} mode={state} valueType="switch" />
</Descriptions.Item>
<Descriptions.Item label="分段选择 segmented">
<DemoField
initialValue="open"
mode={state}
valueType="segmented"
valueEnum={statusEnum}
/>
</Descriptions.Item>
<Descriptions.Item label="远程选择框 select(request)">
<DemoField
initialValue="open"
mode={state}
valueType="select"
request={async () => [
{ label: '全部', value: 'all' },
{ label: '待处理', value: 'open' },
{ label: '已完成', value: 'closed' },
{ label: '进行中', value: 'processing' },
]}
/>
</Descriptions.Item>
<Descriptions.Item label="级联选择 cascader">
<DemoField
initialValue={['zhejiang', 'hangzhou', 'xihu']}
mode={state}
valueType="cascader"
fieldProps={{
fieldNames: { label: 'name' },
}}
request={async () => [
{
value: 'zhejiang',
name: '浙江省',
children: [
{
value: 'hangzhou',
name: '杭州市',
children: [{ value: 'xihu', name: '西湖区' }],
},
],
},
{
value: 'jiangsu',
name: '江苏省',
children: [
{
value: 'nanjing',
name: '南京市',
children: [{ value: 'gulou', name: '鼓楼区' }],
},
],
},
]}
/>
</Descriptions.Item>
<Descriptions.Item label="树形选择 treeSelect">
<DemoField
initialValue="tech-fe"
mode={state}
valueType="treeSelect"
fieldProps={{
options: [
{
label: '技术研发部',
value: 'tech',
children: [
{ label: '前端开发组', value: 'tech-fe' },
{ label: '后端开发组', value: 'tech-be' },
],
},
{
label: '产品设计部',
value: 'product',
children: [
{ label: '产品策划组', value: 'product-pm' },
{ label: 'UX 设计组', value: 'product-ux' },
],
},
],
}}
/>
</Descriptions.Item>
<Descriptions.Item label="颜色选择 color">
<DemoField initialValue="#1677FF" mode={state} valueType="color" />
</Descriptions.Item>
</Descriptions>
<Descriptions column={2} title="日期时间类">
<Descriptions.Item label="日期 date">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="date"
/>
</Descriptions.Item>
<Descriptions.Item label="日期时间 dateTime">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="dateTime"
/>
</Descriptions.Item>
<Descriptions.Item label="周 dateWeek">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="dateWeek"
/>
</Descriptions.Item>
<Descriptions.Item label="月 dateMonth">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="dateMonth"
/>
</Descriptions.Item>
<Descriptions.Item label="季度 dateQuarter">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="dateQuarter"
/>
</Descriptions.Item>
<Descriptions.Item label="年 dateYear">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="dateYear"
/>
</Descriptions.Item>
<Descriptions.Item label="时间 time">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="time"
/>
</Descriptions.Item>
<Descriptions.Item label="相对时间 fromNow">
<DemoField
initialValue={DEMO_TIMESTAMP}
mode={state}
valueType="fromNow"
/>
</Descriptions.Item>
</Descriptions>
<Descriptions column={2} title="日期范围类">
<Descriptions.Item label="日期范围 dateRange">
<DemoField
initialValue={[
dayjs('2024-01-01').valueOf(),
dayjs('2024-01-31').valueOf(),
]}
mode={state}
valueType="dateRange"
/>
</Descriptions.Item>
<Descriptions.Item label="日期时间范围 dateTimeRange">
<DemoField
initialValue={[
dayjs('2024-01-01 09:00:00').valueOf(),
dayjs('2024-01-31 18:00:00').valueOf(),
]}
mode={state}
valueType="dateTimeRange"
/>
</Descriptions.Item>
<Descriptions.Item label="时间范围 timeRange">
<DemoField
initialValue={[
dayjs('2024-01-01 09:00:00').valueOf(),
dayjs('2024-01-01 18:00:00').valueOf(),
]}
mode={state}
valueType="timeRange"
/>
</Descriptions.Item>
<Descriptions.Item label="周范围 dateWeekRange">
<DemoField
initialValue={[
dayjs('2024-01-01').valueOf(),
dayjs('2024-01-14').valueOf(),
]}
mode={state}
valueType="dateWeekRange"
/>
</Descriptions.Item>
<Descriptions.Item label="月范围 dateMonthRange">
<DemoField
initialValue={[
dayjs('2024-01-01').valueOf(),
dayjs('2024-06-30').valueOf(),
]}
mode={state}
valueType="dateMonthRange"
/>
</Descriptions.Item>
<Descriptions.Item label="季度范围 dateQuarterRange">
<DemoField
initialValue={[
dayjs('2024-01-01').valueOf(),
dayjs('2024-09-30').valueOf(),
]}
mode={state}
valueType="dateQuarterRange"
/>
</Descriptions.Item>
<Descriptions.Item label="年范围 dateYearRange">
<DemoField
initialValue={[
dayjs('2023-01-01').valueOf(),
dayjs('2025-12-31').valueOf(),
]}
mode={state}
valueType="dateYearRange"
/>
</Descriptions.Item>
</Descriptions>
<Descriptions column={2} title="代码类">
<Descriptions.Item label="代码块 code">
<DemoField
initialValue={`pnpm install
pnpm run build
pnpm run deploy --env production`}
mode={state}
valueType="code"
/>
</Descriptions.Item>
<Descriptions.Item label="JSON 代码块 jsonCode">
<DemoField
initialValue={`{
"service": "user-auth",
"port": 8080,
"replicas": 3
}`}
mode={state}
valueType="jsonCode"
/>
</Descriptions.Item>
</Descriptions>
</div>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
空字符串- | 头像 |
文本 | 颜色 |
颜色禁用 | 图片 |
金额 | 数字 |
数字范围 | 秒格式化 |
百分比 | 评分 |
slider | 选择框 请选择 |
多选 | 多选 labelInValue |
单选 | 单选按钮 |
远程选择框 请选择 | 远程级联框 请选择 |
进度条 | 进度条 |
进度条 | 百分比空值- |
百分比 10.00% 0.00% - 10.00% | 日期时间 |
相对于当前时间 | 日期 |
日期区间 | 日期时间区间 |
时间 | 时间区间 |
密码 | 代码块 |
JSON 代码块 | |
ProField 基础测试 Props 说明:
- text: 显示的文本内容
- mode: 显示模式,'read' 表示只读,'edit' 表示编辑
- valueType: 值类型,决定如何渲染内容
- fieldProps: 字段属性配置
- disabled: 是否禁用
Radio.Group 配置:
- onChange: 值变化回调函数
- value: 当前选中的值
- 模式切换: 用于切换 ProField 的显示模式
Switch 配置:
- checked: 是否选中
- onChange: 值变化回调函数
- 简约模式: 控制是否使用简约模式
Descriptions 配置:
- column: 列数配置
- 内容展示: 用于展示各种 ProField 组件
支持的 valueType 类型:
- text: 文本类型
- avatar: 头像类型
- color: 颜色类型
- image: 图片类型
- money: 金额类型
- digit: 数字类型
- date: 日期类型
- dateRange: 日期区间类型
- dateTimeRange: 日期时间区间类型
- time: 时间类型
- timeRange: 时间区间类型
- password: 密码类型
- code: 代码块类型
- jsonCode: JSON 代码块类型
fieldProps 配置:
- disabled: 是否禁用字段
- precision: 数字精度
- style: 样式配置
- customSymbol: 自定义货币符号
- width: 图片宽度
显示模式特点:
- 只读模式: 仅显示内容,不可编辑
- 编辑模式: 可以编辑内容
- 简约模式: 使用简约的显示样式
- 动态切换: 支持动态切换显示模式
布局特点:
- 控制区域: 顶部显示模式切换控制
- 展示区域: 使用 Descriptions 展示各种字段类型
- 响应式设计: 自动适配不同屏幕尺寸
- 网格 布局: 使用网格布局展示多个字段
使用场景:
- 字段测试: 测试各种字段类型的显示效果
- 模式切换: 测试只读和编辑模式的切换
- 样式测试: 测试简约模式和普通模式的样式差异
- 功能验证: 验证各种字段类型的功能
最佳实践:
- 类型选择: 根据数据类型选择合适的 valueType
- 模式设计: 合理设计只读和编辑模式
- 样式配置: 根据需求配置合适的样式
- 用户体验: 提供清晰的模式切换和内容展示
import type { ProFieldFCMode } from '@ant-design/pro-components';
import { ProField } from '@ant-design/pro-components';
import { Descriptions, Radio, Space } from 'antd';
import dayjs from 'dayjs';
import { useState } from 'react';
const Demo = () => {
const [state, setState] = useState<ProFieldFCMode>('edit');
return (
<>
<Space>
<Radio.Group
onChange={(e) => setState(e.target.value as ProFieldFCMode)}
value={state}
>
<Radio value="read">只读</Radio>
<Radio value="edit">编辑</Radio>
</Radio.Group>
</Space>
<br />
<br />
<Descriptions column={2}>
<Descriptions.Item label="空字符串">
<ProField text="" mode="read" />
</Descriptions.Item>
<Descriptions.Item label="头像">
<ProField
text="https://avatars2.githubusercontent.com/u/8186664?s=60&v=4"
mode="read"
valueType="avatar"
/>
</Descriptions.Item>
<Descriptions.Item label="文本">
<ProField
text="这是一段文本"
fieldProps={{
disabled: true,
}}
valueType="text"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="颜色">
<ProField text="blue" valueType="color" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="颜色禁用">
<ProField
text="blue"
valueType="color"
fieldProps={{
disabled: true,
}}
mode={state}
/>
<ProField text="blue" valueType="color" disabled mode="read" />
</Descriptions.Item>
<Descriptions.Item label="图片">
<ProField
text="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
valueType={{
type: 'image',
width: 100,
}}
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="金额">
<ProField
numberPopoverRender
fieldProps={{
precision: 2,
style: {
width: 200,
},
}}
text="10000"
valueType="money"
mode={state}
/>
<ProField
valueType="money"
label="自定义货币符号"
name="amount4"
fieldProps={{
value: 2221212.22,
customSymbol: '💰',
}}
mode="read"
/>
</Descriptions.Item>
<Descriptions.Item label="数字">
<ProField
text="19897979797979"
valueType="digit"
fieldProps={{
min: 1,
max: 10000,
precision: 0,
formatter: null,
}}
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="数字范围">
<ProField text={[123, 456]} valueType="digitRange" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="秒格式化">
<ProField text={2000000} valueType="second" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="百分比">
<ProField text="100" valueType="percent" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="评分">
<ProField text={3.5} valueType="rate" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="slider">
<ProField text="40" valueType="slider" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="选择框">
<ProField
text="open"
mode={state}
valueEnum={{
all: { text: '全部', disabled: true, status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
},
processing: {
text: '解决中',
status: 'Processing',
},
}}
/>
</Descriptions.Item>
<Descriptions.Item label="多选">
<ProField
text={['open', 'closed']}
mode={state}
valueType="checkbox"
valueEnum={{
all: { text: '全部', disabled: true, status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
},
processing: {
text: '解决中',
status: 'Processing',
},
}}
/>
</Descriptions.Item>
<Descriptions.Item label="多选 labelInValue">
<ProField
text={[
{
value: 'open1',
label: '打开',
},
{
value: 'closed2',
label: '关闭',
},
]}
mode={state}
valueType="checkbox"
valueEnum={{
all: { text: '全部', disabled: true, status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
},
processing: {
text: '解决中',
status: 'Processing',
},
}}
/>
</Descriptions.Item>
<Descriptions.Item label="单选">
<ProField
text="open"
mode={state}
valueType="radio"
fieldProps={{
layout: 'horizontal',
}}
valueEnum={{
all: { text: '全部', disabled: true, status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
},
processing: {
text: '解决中',
status: 'Processing',
},
}}
/>
</Descriptions.Item>
<Descriptions.Item label="单选按钮">
<ProField
text="open"
mode={state}
valueType="radioButton"
valueEnum={{
all: { text: '全部', disabled: true, status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
},
processing: {
text: '解决中',
status: 'Processing',
},
}}
/>
</Descriptions.Item>
<Descriptions.Item label="远程选择框">
<ProField
text="open"
mode={state}
params={{
name: 'test',
}}
valueType="select"
request={async () => {
return [
{ label: '全部', value: 'all' },
{ label: '未解决', value: 'open' },
{ label: '已解决', value: 'closed' },
{ label: '解决中', value: 'processing' },
{
label: '特殊选项',
value: 'optGroup',
optionType: 'optGroup',
options: [
{ label: '不解决', value: 'no' },
{ label: '已废弃', value: 'clear' },
],
},
];
}}
/>
</Descriptions.Item>
<Descriptions.Item label="远程级联框">
<ProField
mode={state}
params={{
name: 'test',
}}
valueType="cascader"
request={async () => {
return [
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
],
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
children: [
{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
},
],
},
],
},
];
}}
/>
</Descriptions.Item>
<Descriptions.Item label="进度条">
<ProField text="40" valueType="progress" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="进度条">
<ProField text="40%" valueType="progress" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="进度条">
<ProField text="love" valueType="progress" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="百分比空值">
<ProField valueType="percent" mode="read" />
</Descriptions.Item>
<Descriptions.Item label="百分比">
<Space>
<ProField
text={10}
valueType={{
type: 'percent',
showSymbol: (text: number) => {
if (text < 0) {
return true;
}
return false;
},
showColor: true,
}}
mode="read"
/>
<ProField
text={0}
valueType={{
type: 'percent',
showSymbol: true,
showColor: true,
}}
mode="read"
/>
<ProField
text={-10}
valueType={{
type: 'percent',
showSymbol: true,
showColor: true,
}}
mode="read"
/>
</Space>
</Descriptions.Item>
<Descriptions.Item label="日期时间">
<ProField
text={dayjs('2019-11-16 12:50:26').valueOf()}
valueType="dateTime"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="相对于当前时间">
<Space>
<ProField
text={dayjs('2019-11-16 12:50:26').valueOf()}
valueType="fromNow"
mode={state}
/>
<ProField
text={dayjs('2020-11-16 12:50:26').valueOf()}
valueType="fromNow"
mode={state}
/>
</Space>
</Descriptions.Item>
<Descriptions.Item label="日期">
<ProField
text={dayjs('2019-11-16 12:50:26').valueOf()}
valueType="date"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="日期区间">
<ProField
text={[
dayjs('2019-11-16 12:50:26').add(-1, 'd').valueOf(),
dayjs('2019-11-16 12:50:26').valueOf(),
]}
valueType="dateRange"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="日期时间区间">
<ProField
text={[
dayjs('2019-11-16 12:50:26').add(-1, 'd').valueOf(),
dayjs('2019-11-16 12:50:26').valueOf(),
]}
valueType="dateTimeRange"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="时间">
<ProField
text={dayjs('2019-11-16 12:50:26').valueOf()}
valueType="time"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="时间区间">
<ProField
text={[
dayjs('2019-11-16 12:50:26').add(-1, 'd').valueOf(),
dayjs('2019-11-16 12:50:26').valueOf(),
]}
valueType="timeRange"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="密码">
<ProField text="password" valueType="password" mode={state} />
</Descriptions.Item>
<Descriptions.Item label="代码块">
<ProField
text={`
yarn run v1.22.0
$ eslint --format=pretty ./packages
Done in 9.70s.
`}
valueType="code"
mode={state}
/>
</Descriptions.Item>
<Descriptions.Item label="JSON 代码块">
<ProField
text={`{
"compilerOptions": {
"target": "esnext",
"moduleResolution": "node",
"jsx": "preserve",
"esModuleInterop": true,
"experimentalDecorators": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"declaration": true,
"skipLibCheck": true
},
"include": ["**/src", "**/docs", "scripts", "**/demo", ".eslintrc.js"]
}
`}
valueType="jsonCode"
mode={state}
/>
</Descriptions.Item>
</Descriptions>
<div
style={{
marginTop: '20px',
padding: '20px',
backgroundColor: '#f5f5f5',
borderRadius: '6px',
}}
>
<h4>ProField 基础测试 Props 说明:</h4>
<ul>
<li>
<strong>text</strong>: 显示的文本内容
</li>
<li>
<strong>mode</strong>: 显示模式,'read' 表示只读,'edit' 表示编辑
</li>
<li>
<strong>valueType</strong>: 值类型,决定如何渲染内容
</li>
<li>
<strong>fieldProps</strong>: 字段属性配置
</li>
<li>
<strong>disabled</strong>: 是否禁用
</li>
</ul>
<h4>Radio.Group 配置:</h4>
<ul>
<li>
<strong>onChange</strong>: 值变化回调函数
</li>
<li>
<strong>value</strong>: 当前选中的值
</li>
<li>
<strong>模式切换</strong>: 用于切换 ProField 的显示模式
</li>
</ul>
<h4>Switch 配置:</h4>
<ul>
<li>
<strong>checked</strong>: 是否选中
</li>
<li>
<strong>onChange</strong>: 值变化回调函数
</li>
<li>
<strong>简约模式</strong>: 控制是否使用简约模式
</li>
</ul>
<h4>Descriptions 配置:</h4>
<ul>
<li>
<strong>column</strong>: 列数配置
</li>
<li>
<strong>内容展示</strong>: 用于展示各种 ProField 组件
</li>
</ul>
<h4>支持的 valueType 类型:</h4>
<ul>
<li>
<strong>text</strong>: 文本类型
</li>
<li>
<strong>avatar</strong>: 头像类型
</li>
<li>
<strong>color</strong>: 颜色类型
</li>
<li>
<strong>image</strong>: 图片类型
</li>
<li>
<strong>money</strong>: 金额类型
</li>
<li>
<strong>digit</strong>: 数字类型
</li>
<li>
<strong>date</strong>: 日期类型
</li>
<li>
<strong>dateRange</strong>: 日期区间类型
</li>
<li>
<strong>dateTimeRange</strong>: 日期时间区间类型
</li>
<li>
<strong>time</strong>: 时间类型
</li>
<li>
<strong>timeRange</strong>: 时间区间类型
</li>
<li>
<strong>password</strong>: 密码类型
</li>
<li>
<strong>code</strong>: 代码块类型
</li>
<li>
<strong>jsonCode</strong>: JSON 代码块类型
</li>
</ul>
<h4>fieldProps 配置:</h4>
<ul>
<li>
<strong>disabled</strong>: 是否禁用字段
</li>
<li>
<strong>precision</strong>: 数字精度
</li>
<li>
<strong>style</strong>: 样式配置
</li>
<li>
<strong>customSymbol</strong>: 自定义货币符号
</li>
<li>
<strong>width</strong>: 图片宽度
</li>
</ul>
<h4>显示模式特点:</h4>
<ul>
<li>
<strong>只读模式</strong>: 仅显示内容,不可编辑
</li>
<li>
<strong>编辑模式</strong>: 可以编辑内容
</li>
<li>
<strong>简约模式</strong>: 使用简约的显示样式
</li>
<li>
<strong>动态切换</strong>: 支持动态切换显示模式
</li>
</ul>
<h4>布局特点:</h4>
<ul>
<li>
<strong>控制区域</strong>: 顶部显示模式切换控制
</li>
<li>
<strong>展示区域</strong>: 使用 Descriptions 展示各种字段类型
</li>
<li>
<strong>响应式设计</strong>: 自动适配不同屏幕尺寸
</li>
<li>
<strong>网格布局</strong>: 使用网格布局展示多个字段
</li>
</ul>
<h4>使用场景:</h4>
<ul>
<li>
<strong>字段测试</strong>: 测试各种字段类型的显示效果
</li>
<li>
<strong>模式切换</strong>: 测试只读和编辑模式的切换
</li>
<li>
<strong>样式测试</strong>: 测试简约模式和普通模式的样式差异
</li>
<li>
<strong>功能验证</strong>: 验证各种字段类型的功能
</li>
</ul>
<h4>最佳实践:</h4>
<ul>
<li>
<strong>类型选择</strong>: 根据数据类型选择合适的 valueType
</li>
<li>
<strong>模式设计</strong>: 合理设计只读和编辑模式
</li>
<li>
<strong>样式配置</strong>: 根据需求配置合适的样式
</li>
<li>
<strong>用户体验</strong>: 提供清晰的模式切换和内容展示
</li>
</ul>
</div>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
常用关键字:lca
import { ProForm, ProFormSelect } from '@ant-design/pro-components';
import { useState } from 'react';
export function App() {
const [searchValue, setSearchValue] = useState('');
const [selectOpen, setSelectOpen] = useState(false);
function onBlur() {
setSelectOpen(false);
}
function onFocus() {
setSelectOpen(true);
}
/** 点击常用关键字的字母 */
function onClick(e: any) {
const text = e.target as HTMLSpanElement;
// 更改搜索框文字
setSearchValue(text.innerText);
onFocus();
}
/** 下拉搜索 */
function onSearch(value: string) {
setSearchValue(value);
}
/** 下拉选中 */
function onSelect() {
onBlur();
}
return (
<div>
<ProForm>
<ProFormSelect
name="name"
placeholder="请输入搜索关键字"
allowClear
width={330}
secondary
options={
[
{
v: 'v1',
l: 'l1',
},
{
v: 'v2',
l: 'l3',
},
{
v: 'v4',
l: 'l5',
},
] as any
}
fieldProps={{
fieldNames: {
value: 'v',
label: 'l',
options: 'options',
},
suffixIcon: null,
showSearch: true, // 使单选模式可搜索
popupMatchSelectWidth: false,
optionFilterProp: 'label', // 搜索时过滤对应的 option 属性
optionLabelProp: 'label', // 回填到选择框的 Option 的属性值
searchValue,
open: selectOpen,
onBlur: () => onBlur(),
onFocus: () => onFocus(),
onSearch: (val) => onSearch(val),
onSelect: () => onSelect(),
}}
/>
</ProForm>
<div className="keys">
<b>常用关键字:</b>
{['l', 'c', 'a'].map((item) => {
return (
<span
key={item}
onClick={onClick}
style={{
marginInlineStart: 8,
cursor: 'pointer',
}}
>
{item}
</span>
);
})}
</div>
</div>
);
}
export default () => (
<div style={{ padding: 24 }}>
<App />
</div>
);
ProFormSelect 搜索值自动清除 Props 说明:
- name: 字段名
- placeholder: 占位符文本
- allowClear: 是否允许清除
- width: 控件宽度
- secondary: 是否使用次要样式
- mode: 选择模式,'tags' 表示标签模式
- options: 选项数组
- fieldProps: 字段属性配置
fieldProps 配置:
- fieldNames: 字段名映射配置
- showSearch: 是否显示搜索功能
- autoClearSearchValue: 是否自动清除搜索值
fieldNames 配置:
- value: 值字段名
- label: 标签字段名
- options: 选项字段名
- 字段映射: 将自定义字段名映射为标准字段名
选项配置:
- v: 选项值
- l: 选项标签
- 自定义字段: 使用自定义字段名结构
搜索功能特点:
- 搜索输入: 支持输入关键字进行搜索
- 自动清除: 选择后自动清除搜索框的值
- 标签模式: 支持多选标签模式
- 字段映射: 支持自定义字段名映射
布局特点:
- 固定宽度: 使用固定宽度 330px
- 次要样式: 使用次要样式显示
- 响应式设计: 自动适配不同屏幕尺寸
- 清晰布局: 提供清晰的输入和选择界面
使用场景:
- 多选搜索: 需要多选和搜索功能的场景
- 自定义字段: 使用自定义字段名结构的场景
- 自动清除: 需要选择后自动清除搜索值的场景
- 标签选择: 需要标签形式多选的场景
最佳实践:
- 字段映射: 合理配置字段名映射关系
- 搜索配置: 根据需求配置搜索功能
- 自动清除: 合理使用自动清除功能
- 用户体验: 提供清晰的搜索和选择体验
import { ProForm, ProFormSelect } from '@ant-design/pro-components';
export function App() {
return (
<div>
<ProForm>
<ProFormSelect
name="name"
placeholder="请输入搜索关键字"
allowClear
width={330}
secondary
mode="tags"
options={
[
{
v: 'v1',
l: 'l1',
},
{
v: 'v2',
l: 'l3',
},
{
v: 'v4',
l: 'l5',
},
] as any
}
fieldProps={{
fieldNames: {
value: 'v',
label: 'l',
options: 'options',
},
showSearch: true, // 使单选模式可搜索
autoClearSearchValue: true,
}}
/>
</ProForm>
<div
style={{
marginTop: '20px',
padding: '20px',
backgroundColor: '#f5f5f5',
borderRadius: '6px',
}}
>
<h4>ProFormSelect 搜索值自动清除 Props 说明:</h4>
<ul>
<li>
<strong>name</strong>: 字段名
</li>
<li>
<strong>placeholder</strong>: 占位符文本
</li>
<li>
<strong>allowClear</strong>: 是否允许清除
</li>
<li>
<strong>width</strong>: 控件宽度
</li>
<li>
<strong>secondary</strong>: 是否使用次要样式
</li>
<li>
<strong>mode</strong>: 选择模式,'tags' 表示标签模式
</li>
<li>
<strong>options</strong>: 选项数组
</li>
<li>
<strong>fieldProps</strong>: 字段属性配置
</li>
</ul>
<h4>fieldProps 配置:</h4>
<ul>
<li>
<strong>fieldNames</strong>: 字段名映射配置
</li>
<li>
<strong>showSearch</strong>: 是否显示搜索功能
</li>
<li>
<strong>autoClearSearchValue</strong>: 是否自动清除搜索值
</li>
</ul>
<h4>fieldNames 配置:</h4>
<ul>
<li>
<strong>value</strong>: 值字段名
</li>
<li>
<strong>label</strong>: 标签字段名
</li>
<li>
<strong>options</strong>: 选项字段名
</li>
<li>
<strong>字段映射</strong>: 将自定义字段名映射为标准字段名
</li>
</ul>
<h4>选项配置:</h4>
<ul>
<li>
<strong>v</strong>: 选项值
</li>
<li>
<strong>l</strong>: 选项标签
</li>
<li>
<strong>自定义字段</strong>: 使用自定义字段名结构
</li>
</ul>
<h4>搜索功能特点:</h4>
<ul>
<li>
<strong>搜索输入</strong>: 支持输入关键字进行搜索
</li>
<li>
<strong>自动清除</strong>: 选择后自动清除搜索框的值
</li>
<li>
<strong>标签模式</strong>: 支持多选标签模式
</li>
<li>
<strong>字段映射</strong>: 支持自定义字段名映射
</li>
</ul>
<h4>布局特点:</h4>
<ul>
<li>
<strong>固定宽度</strong>: 使用固定宽度 330px
</li>
<li>
<strong>次要样式</strong>: 使用次要样式显示
</li>
<li>
<strong>响应式设计</strong>: 自动适配不同屏幕尺寸
</li>
<li>
<strong>清晰布局</strong>: 提供清晰的输入和选择界面
</li>
</ul>
<h4>使用场景:</h4>
<ul>
<li>
<strong>多选搜索</strong>: 需要多选和搜索功能的场景
</li>
<li>
<strong>自定义字段</strong>: 使用自定义字段名结构的场景
</li>
<li>
<strong>自动清除</strong>: 需要选择后自动清除搜索值的场景
</li>
<li>
<strong>标签选择</strong>: 需要标签形式多选的场景
</li>
</ul>
<h4>最佳实践:</h4>
<ul>
<li>
<strong>字段映射</strong>: 合理配置字段名映射关系
</li>
<li>
<strong>搜索配置</strong>: 根据需求配置搜索功能
</li>
<li>
<strong>自动清除</strong>: 合理使用自动清除功能
</li>
<li>
<strong>用户体验</strong>: 提供清晰的搜索和选择体验
</li>
</ul>
</div>
</div>
);
}
export default () => (
<div style={{ padding: 24 }}>
<App />
</div>
);
import { ProForm, ProFormTreeSelect } from '@ant-design/pro-components';
import { message } from 'antd';
import { useState } from 'react';
const treeData = [
{
title: '技术研发部',
treeValue: '0-0',
children: [
{
title: '前端开发组',
treeValue: '0-0-0',
},
],
},
{
title: '产品设计部',
treeValue: '0-1',
children: [
{
title: '产品 策划组',
treeValue: '0-1-0',
},
{
title: 'UX 设计组',
treeValue: '0-1-1',
},
{
title: '用户研究组',
treeValue: '0-1-2',
},
],
},
];
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
export function App() {
const [searchValue, setSearchValue] = useState('');
const [selectOpen, setSelectOpen] = useState(false);
function onBlur() {
setSelectOpen(false);
}
function onFocus() {
setSelectOpen(true);
}
/** 点击常用关键字的字母 */
function onClick(e: any) {
const text = e.target as HTMLSpanElement;
// 更改搜索框文字
setSearchValue(text.innerText);
onFocus();
}
/** 下拉搜索 */
function onSearch(value: string) {
setSearchValue(value);
}
return (
<div>
<ProForm
initialValues={{
name: ['0-0'],
}}
onFinish={async () => {
message.success('提交成功');
}}
>
<ProFormTreeSelect
name="name"
placeholder="请输入搜索关键字"
allowClear
width={330}
label="TreeSelect异步加载"
secondary
request={async () => {
await waitTime(1000);
return treeData;
}}
fieldProps={{
suffixIcon: null,
filterTreeNode: true,
showSearch: true, // 使单选模式可搜索
popupMatchSelectWidth: false,
searchValue,
labelInValue: true,
autoClearSearchValue: true,
open: selectOpen,
multiple: true,
treeNodeFilterProp: 'title',
fieldNames: {
label: 'title',
value: 'treeValue',
},
onBlur: () => onBlur(),
onFocus: () => onFocus(),
onSearch: (val) => onSearch(val),
}}
/>
<ProFormTreeSelect
name="name2"
initialValue={['0-0', '0-1']}
label="TreeSelect treeData"
placeholder="请输入搜索关键字"
allowClear
width={330}
secondary
fieldProps={{
treeData,
suffixIcon: null,
filterTreeNode: true,
showSearch: true, // 使单选模式可搜索
popupMatchSelectWidth: false,
labelInValue: true,
autoClearSearchValue: true,
multiple: true,
treeNodeFilterProp: 'title',
fieldNames: {
label: 'title',
value: 'treeValue',
},
}}
/>
<div className="keys">
<b>常用关键字:</b>
{['l', 'c', 'a'].map((item) => {
return (
<span
key={item}
onClick={onClick}
style={{
marginInlineStart: 8,
cursor: 'pointer',
}}
>
{item}
</span>
);
})}
</div>
</ProForm>
</div>
);
}
export default () => (
<div style={{ padding: 24 }}>
<App />
</div>
);
import { ProForm, ProFormSelect } from '@ant-design/pro-components';
function App() {
return (
<div className="App">
<ProForm>
<ProFormSelect
showSearch
name="select"
request={async () => [{ label: '选项1', value: '1' }]}
/>
</ProForm>
<ProForm>
<ProFormSelect
showSearch
name="select"
request={async () => [{ label: '选项2', value: '2' }]}
/>
</ProForm>
</div>
);
}
export default () => (
<div style={{ padding: 24 }}>
<App />
</div>
);
import { ProForm, ProFormSelect } from '@ant-design/pro-components';
function App() {
return (
<div className="App">
<ProForm>
<ProFormSelect
showSearch
name="remote"
label="远程搜索(默认)"
request={async ({ keyWords }: any) => {
console.log('remote request called:', keyWords);
return [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
].filter((item) => item.label.includes(keyWords || ''));
}}
/>
<ProFormSelect
showSearch
name="local"
label="本地搜索(request 只拉取一次)"
fetchDataOnSearch={false}
request={async () => [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
]}
/>
</ProForm>
</div>
);
}
export default () => (
<div style={{ padding: 24 }}>
<App />
</div>
);
#API
import Field from '@ant-design/pro-field';
return <Field text="100" valueType="money" mode={state} />;#参数
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| text | 需要格式化的值 | ReactNode | ReactNode[] | Record<string,any> | Record<string,any>[] | - |
| valueType | 格式化的类型 | ProFieldValueTypeInput | - |
| mode | 组件的模式 | read | edit | update | read |
| readonly | 是否只读 | boolean | - |
| request | 从服务器读取枚举 | (params, props) => Promise<RequestOptionsType[]> | - |
| emptyText | 空值时的展示 | ReactNode | - |
| formItemRender | 自定义 mode=update | edit 下的 dom 表现,一般用于渲染编辑框 | (text, props, dom) => JSX.Element | - |
| render | 自定义 mode=read 下的 dom 表现,只是单纯的表现形式 | (text, props, dom) => JSX.Element | - |
