ProFormFields
19 个独立字段组件为普通表单、自定义布局、ProTable 搜索与行内编辑、SchemaForm 提供同一套值绑定、选项请求和只读展示协议。默认组件自带 Antdv Next FormItem;需要只渲染控件时使用 fieldMode="field"。
完整字段示例
下面的 Vue SFC 示例实际渲染全部 19 个公开字段,并演示只读态、异步选项、验证码回调、上传入口和裸控件模式。
查看完整代码
<script setup lang="ts">
import type { UploadFile } from 'antdv-next'
import { Form } from 'antdv-next'
import { computed, reactive, ref } from 'vue'
import { useData } from 'vitepress'
import {
ProFormCaptcha,
ProFormCheckbox,
ProFormDatePicker,
ProFormDateRangePicker,
ProFormDateTimePicker,
ProFormDateTimeRangePicker,
ProFormDigit,
ProFormMoney,
ProFormRadioGroup,
ProFormSegmented,
ProFormSelect,
ProFormSlider,
ProFormSwitch,
ProFormText,
ProFormTextArea,
ProFormTextPassword,
ProFormTreeSelect,
ProFormUploadButton,
ProFormUploadDragger,
type ProFormDateRangeValue,
type ProFormDateValue,
} from 'antdv-next-pro'
interface DemoModel {
text?: string
digit?: number | string | null
password?: string
textarea?: string
captcha?: string
date?: ProFormDateValue
dateTime?: ProFormDateValue
dateRange?: ProFormDateRangeValue
dateTimeRange?: ProFormDateRangeValue
select?: string
treeSelect?: string
checkbox?: string[]
radio?: string
slider?: number | number[]
switch?: boolean
uploadButton: UploadFile[]
uploadDragger: UploadFile[]
money?: number | string | null
segmented?: string | number
bareText?: string
bareChecked?: boolean
}
const { lang } = useData()
const english = computed(() => lang.value.startsWith('en'))
const readonly = ref(false)
const captchaStatus = ref('')
const model = reactive<DemoModel>({
text: 'Antdv Next Pro',
digit: 2,
password: 'vue-vapor',
textarea: 'One field core for forms, tables, and editable cells.',
select: 'vue',
treeSelect: 'pro-form-fields',
checkbox: ['docs', 'tests'],
radio: 'named',
slider: 68,
switch: true,
uploadButton: [],
uploadDragger: [],
money: 128,
segmented: 'preview',
bareText: 'fieldMode="field"',
bareChecked: true,
})
const tr = (zh: string, en: string) => (english.value ? en : zh)
const selectOptions = computed(() => [
{ label: 'Vue 3', value: 'vue' },
{ label: 'Antdv Next', value: 'antdv-next' },
])
const treeOptions = computed(() => [
{
label: tr('字段体系', 'Field system'),
value: 'fields',
children: [
{ label: 'ProFormFields', value: 'pro-form-fields' },
{ label: 'SchemaForm', value: 'schema-form' },
],
},
])
const checkboxOptions = computed(() => [
{ label: tr('文档', 'Docs'), value: 'docs' },
{ label: tr('测试', 'Tests'), value: 'tests' },
{ label: tr('构建', 'Build'), value: 'build' },
])
const radioOptions = computed(() => [
{ label: tr('具名导入', 'Named import'), value: 'named' },
{ label: tr('全局注册', 'Global registration'), value: 'global' },
])
const segmentedOptions = computed(() => [
{ label: tr('编辑', 'Edit'), value: 'edit' },
{ label: tr('预览', 'Preview'), value: 'preview' },
])
async function requestSelectOptions() {
await Promise.resolve()
return selectOptions.value
}
async function getCaptcha() {
await Promise.resolve()
captchaStatus.value = tr('发送逻辑由当前示例提供', 'The demo supplied the send callback')
}
</script>
<template>
<div class="demo-frame pro-form-fields-demo vp-raw">
<div class="demo-heading">
<div>
<p class="demo-label">LIVE · 19 PRO FORM FIELDS</p>
<p class="demo-note">
{{
tr(
'所有字段共享相同的表单项、裸控件、只读与选项协议。',
'Every field shares the same form-item, bare-control, readonly, and option protocols.',
)
}}
</p>
</div>
<button type="button" @click="readonly = !readonly">
{{ readonly ? tr('返回编辑', 'Edit values') : tr('查看只读', 'Readonly view') }}
</button>
</div>
<Form :model="model" layout="vertical">
<div class="field-grid">
<ProFormText
v-model="model.text"
:label="tr('文本', 'Text')"
:readonly="readonly"
:field-props="{ allowClear: true }"
>
<template #extra>
{{ tr('默认包含 FormItem', 'FormItem is included by default') }}
</template>
</ProFormText>
<ProFormDigit v-model="model.digit" :label="tr('数字', 'Digit')" :readonly="readonly" />
<ProFormTextPassword
v-model="model.password"
:label="tr('密码', 'Password')"
:readonly="readonly"
/>
<ProFormTextArea
v-model="model.textarea"
class="span-2"
:label="tr('多行文本', 'Text area')"
:readonly="readonly"
:field-props="{ rows: 3 }"
/>
<ProFormCaptcha
v-model="model.captcha"
class="span-2"
:label="tr('验证码', 'Captcha')"
:readonly="readonly"
:on-get-captcha="getCaptcha"
:count-down="5"
:captcha-text="tr('发送演示验证码', 'Send demo code')"
/>
<ProFormDatePicker v-model="model.date" :label="tr('日期', 'Date')" :readonly="readonly" />
<ProFormDateTimePicker
v-model="model.dateTime"
:label="tr('日期时间', 'Date time')"
:readonly="readonly"
/>
<ProFormDateRangePicker
v-model="model.dateRange"
:label="tr('日期区间', 'Date range')"
:readonly="readonly"
/>
<ProFormDateTimeRangePicker
v-model="model.dateTimeRange"
:label="tr('日期时间区间', 'Date-time range')"
:readonly="readonly"
/>
<ProFormSelect
v-model="model.select"
:label="tr('异步选择', 'Async select')"
:readonly="readonly"
:request="requestSelectOptions"
/>
<ProFormTreeSelect
v-model="model.treeSelect"
:label="tr('树选择', 'Tree select')"
:readonly="readonly"
:options="treeOptions"
/>
<ProFormCheckbox
v-model="model.checkbox"
:label="tr('复选组', 'Checkbox group')"
:readonly="readonly"
:options="checkboxOptions"
layout="vertical"
/>
<ProFormRadioGroup
v-model="model.radio"
:label="tr('单选组', 'Radio group')"
:readonly="readonly"
:options="radioOptions"
/>
<ProFormSlider
v-model="model.slider"
:label="tr('滑块', 'Slider')"
:readonly="readonly"
:field-props="{ min: 0, max: 100 }"
/>
<ProFormSwitch v-model="model.switch" :label="tr('开关', 'Switch')" :readonly="readonly" />
<ProFormMoney v-model="model.money" :label="tr('金额', 'Money')" :readonly="readonly" />
<ProFormSegmented
v-model="model.segmented"
:label="tr('分段选择', 'Segmented')"
:readonly="readonly"
:options="segmentedOptions"
/>
<ProFormUploadButton
v-model="model.uploadButton"
:label="tr('按钮上传', 'Upload button')"
:readonly="readonly"
:field-props="{ maxCount: 1 }"
/>
<ProFormUploadDragger
v-model="model.uploadDragger"
class="span-2"
:label="tr('拖拽上传', 'Upload dragger')"
:readonly="readonly"
:field-props="{ multiple: true }"
/>
</div>
</Form>
<div class="bare-fields">
<strong>{{ tr('裸控件模式', 'Bare-control mode') }}</strong>
<ProFormText
v-model="model.bareText"
field-mode="field"
:readonly="readonly"
:placeholder="tr('不会生成 FormItem', 'No FormItem is rendered')"
/>
<ProFormCheckbox v-model="model.bareChecked" field-mode="field" :readonly="readonly">
{{
tr(
'checked / update:checked 已桥接到 v-model',
'checked / update:checked bridged to v-model',
)
}}
</ProFormCheckbox>
</div>
<p v-if="captchaStatus" class="demo-status">{{ captchaStatus }}</p>
</div>
</template>
<style scoped>
.demo-heading {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
margin-bottom: 20px;
}
.demo-heading .demo-label,
.demo-note {
margin: 0;
}
.demo-note {
margin-top: 5px;
color: var(--vp-c-text-2);
font-size: 13px;
}
.demo-heading button {
flex: none;
padding: 6px 12px;
border: 1px solid var(--bubbles-border);
border-radius: 7px;
background: var(--vp-c-bg);
color: var(--vp-c-brand-1);
cursor: pointer;
}
.field-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
column-gap: 20px;
}
.span-2 {
grid-column: span 2;
}
.bare-fields {
display: grid;
grid-template-columns: minmax(120px, 0.45fr) minmax(220px, 1fr) minmax(220px, 1fr);
align-items: center;
gap: 14px;
margin-top: 4px;
padding-top: 18px;
border-top: 1px solid var(--bubbles-border);
}
.demo-status {
margin: 14px 0 0;
color: var(--vp-c-text-2);
font-size: 12px;
}
@media (max-width: 720px) {
.field-grid,
.bare-fields {
grid-template-columns: 1fr;
}
.span-2 {
grid-column: auto;
}
.demo-heading {
flex-direction: column;
}
}
</style>导入与命名
19 个模板友好名称均支持具名导入;安装默认插件后也会注册为同名全局组件。
import {
ProFormCaptcha,
ProFormCheckbox,
ProFormDatePicker,
ProFormDateRangePicker,
ProFormDateTimePicker,
ProFormDateTimeRangePicker,
ProFormDigit,
ProFormMoney,
ProFormRadioGroup,
ProFormSegmented,
ProFormSelect,
ProFormSlider,
ProFormSwitch,
ProFormText,
ProFormTextArea,
ProFormTextPassword,
ProFormTreeSelect,
ProFormUploadButton,
ProFormUploadDragger,
} from 'antdv-next-pro'为对应 Ant Design Pro Components 的组合命名,同时提供:
ProFormText.Password === ProFormTextPassword
ProFormRadio.Group === ProFormRadioGroupVue 模板推荐直接使用 ProFormTextPassword 和 ProFormRadioGroup。ProFormRadio 是只读命名空间对象,不是第 20 个字段组件,也不会作为带点名称全局注册。
通用 API
Props
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | 由组件决定 | undefined | 标准 v-model 值 |
name | string | number | readonly (string | number)[] | — | FormItem 字段名,支持嵌套路径 |
label | VNodeChild | — | FormItem 标签 |
rules | Antdv Next FormItem rules | — | 校验规则 |
fieldMode | 'form-item' | 'field' | 'form-item' | 渲染表单项或裸控件 |
fieldProps | 对应基础控件 Props | — | 传给 Input、Select 等基础控件 |
formItemProps | Antdv Next FormItem Props | — | 只传给 FormItem |
disabled | boolean | false | 保持控件外观并禁止交互 |
readonly | boolean | false | 改用统一只读展示 |
emptyText | VNodeChild | '-' | undefined、null、空字符串的占位 |
readonlyRender | (value) => VNodeChild | — | 自定义只读输出;返回空值时回退默认格式化 |
表单项与裸控件
fieldMode="form-item" 是默认模式,name、label、rules 和 formItemProps 作用于组件创建的 FormItem。
<ProFormText
v-model="form.title"
name="title"
label="标题"
:rules="[{ required: true, message: '请输入标题' }]"
/>当父级已经提供 FormItem,或字段位于表格单元格、自定义网格中时使用裸控件模式。此时不会创建 FormItem,name、label、rules、formItemProps 也不参与渲染。
<ProFormText v-model="keyword" field-mode="field" placeholder="只渲染 Input" />属性优先级与 attrs
同名普通属性按以下顺序取值:
- 组件顶层显式属性。
fieldProps或formItemProps中的同名属性。- 组件默认值。
因此顶层 disabled 会覆盖 fieldProps.disabled,顶层 label 会覆盖 formItemProps.label。内部受控值与更新监听器始终由字段核心写入,使用者回调会被组合,不会覆盖 v-model 更新。
fieldProps.class/style 作用于基础控件,formItemProps.class/style 作用于 FormItem。普通 class、style、data-* 和 aria-* 在表单项模式落到 FormItem,在 field 模式落到基础控件。
v-model 桥接
所有公开组件对外都使用 modelValue / update:modelValue,字段核心会适配基础控件的不同协议:
| 组件类型 | 基础控件协议 | ProFormFields 对外协议 |
|---|---|---|
| Input、InputNumber、日期、Select、Radio、Slider、Segmented | value / update:value | v-model |
| 单 Checkbox、Switch | checked / update:checked | v-model |
| Upload、UploadDragger | fileList / update:fileList | v-model |
fieldProps['onUpdate:value']、fieldProps['onUpdate:checked'] 或 fieldProps['onUpdate:fileList'] 可与组件 v-model 同时使用,每次更新各调用一次。
事件
| 事件 | 适用组件 | 说明 |
|---|---|---|
update:modelValue | 全部 | 规范化后的字段值 |
change | 全部 | 原样转发基础控件的 change 参数 |
requestError | Select、TreeSelect、Checkbox 组、RadioGroup、Segmented | 选项请求失败;已有选项不会被清空 |
captchaError | Captcha | 回调 reject 或返回 false;false 原样作为取消结果 |
drop | 两个 Upload | 原样转发拖拽事件 |
底层事件顺序为:内部模型更新 → fieldProps 处理器 → 包装组件 emit。
插槽与实例方法
label、extra、help、tooltip 是 FormItem 插槽;其他具名插槽和默认插槽会转发给基础控件。fieldMode="field" 时不渲染 FormItem 专属插槽。
- Captcha 增加
captcha插槽,参数为{ seconds }。 - UploadButton 的默认插槽替换上传按钮内容。
- UploadDragger 的默认插槽替换拖拽区内容。
- 选项类组件通过 ref 暴露
refresh(): Promise<void>。 - Captcha 通过 ref 暴露
resetCountdown(): void。
选项、请求与只读
options、valueEnum、request
Select、TreeSelect、Checkbox 组、RadioGroup 与 Segmented 使用相同协议:
<ProFormSelect
ref="selectRef"
v-model="owner"
:options="fallbackOptions"
:params="{ teamId }"
:request="loadOwners"
@request-error="reportError"
/>- 存在
request时立即请求;第一次成功前可以显示本地回退选项。 - 远程请求成功后结果成为权威来源,
[]也是有效结果,不会回退到本地选项。 - 没有
request时,优先级为顶层options→fieldProps.options(TreeSelect 为treeData)→valueEnum。 - 请求失败保留最后一次成功结果;从未成功时保留本地回退,并触发
requestError。 request或params变化会刷新;并发时只有最后一次请求可以更新状态。
选项会按 label ?? text ?? title ?? name ?? value 解析标签,按 value ?? key ?? id 解析值。若 valueEnum 需要严格保留数值 key,请使用 ReadonlyMap,或在枚举项中显式写 value:
const levels = new Map([
[1, { text: '一级' }],
[2, { text: '二级' }],
])
const alternate = {
1: { text: '一级', value: 1 },
}只读与重置
readonly 使用统一的 ReadonlyField,不会依赖各基础控件不同的只读实现。选项显示 label,数组使用逗号连接,日期区间使用 ~,密码显示掩码,金额保留前缀,上传显示文件名。0 和 false 不会被当作空值。
字段都是受控组件:父级重置并传入新的 modelValue 后会立即更新。选项缓存不会因值重置而清空;Captcha 的倒计时需调用 resetCountdown() 显式取消。
19 个组件
以下各项都可以在完整字段示例中直接操作。
ProFormText
单行文本字段,modelValue 为 string | undefined,基础控件是 Input。无额外 Pro 默认值;allowClear、prefix、suffix、maxlength 等通过 fieldProps 传入。
ProFormDigit
数值字段,modelValue 为 number | string | null。默认 min=0、precision=2;顶层 min / precision 优先于 fieldProps,传 false 可不向 InputNumber 下发对应限制。
<ProFormDigit v-model="count" :min="false" :precision="0" />ProFormTextPassword
密码输入,modelValue 为 string | undefined,基础控件是 InputPassword。只读非空值固定显示 ••••••。可使用模板友好名称 ProFormTextPassword,也可在脚本或模板中使用 ProFormText.Password。
ProFormTextArea
多行文本,modelValue 为 string | undefined。rows、autoSize、maxlength 等 TextArea 属性通过 fieldProps 传入。
ProFormCaptcha
验证码输入由 Input 与发送按钮组成。onGetCaptcha 必填;countDown 默认 60 秒,按钮默认文案为“获取验证码”。回调 resolve 且结果不为 false 时开始倒计时,reject 或 false 会恢复按钮并触发 captchaError。
组件不读取手机号、不发送网络请求、不持久化验证码;业务侧必须提供 onGetCaptcha。loading、倒计时、disabled、readonly 任一成立时都会阻止重复点击。
ProFormDatePicker
日期选择器,值保持 Antdv Next 的 Dayjs 协议,不自动转换为字符串或原生 Date。格式、禁用日期、面板等属性通过 fieldProps 传入。
ProFormDateTimePicker
日期时间选择器,值保持 Dayjs;默认 showTime=true,可通过顶层 showTime 或 fieldProps.showTime 传入具体配置。
ProFormDateRangePicker
日期区间选择器,值为 Dayjs 区间或 null;清空时不会合成空字符串。范围预设、禁用日期等通过 fieldProps 传入。
ProFormDateTimeRangePicker
日期时间区间选择器,值保持 Dayjs 区间,默认 showTime=true。
ProFormSelect
选择字段,支持 options、valueEnum、request、params 与 requestError;mode="multiple" / "tags" 等能力通过 fieldProps 使用。ref 暴露 refresh()。
ProFormTreeSelect
树选择字段,共用选项请求协议。标准 option 会映射为带 title、label、value、disabled、children 的树节点;调用者提供的 treeData、fieldNames 等仍可通过 fieldProps 使用。
ProFormCheckbox
没有选项来源时渲染单 Checkbox,内部 checked 自动桥接到 v-model;存在 options、valueEnum、request 或 fieldProps.options 时渲染 CheckboxGroup。layout 默认为 horizontal,也可设为 vertical。
ProFormRadioGroup
单选组,共用选项请求协议;方向、button style 等能力通过底层 RadioGroup 的 fieldProps 使用。模板推荐 ProFormRadioGroup,同时提供 ProFormRadio.Group 命名关系。
ProFormSlider
滑块字段,modelValue 为 number | number[] | undefined。range、marks、min、max、step、tooltip 均通过 fieldProps 透传。
ProFormSwitch
开关字段对外使用 v-model,内部使用 checked / update:checked。checkedValue 与 unCheckedValue 原样保留,不会强制把自定义值转换为 Boolean。
ProFormUploadButton
按钮式上传入口,modelValue 为 UploadFile[],内部桥接 fileList。默认槽可替换按钮内容;action、customRequest、beforeUpload、headers、data、multiple、accept、maxCount、itemRender 等通过 fieldProps 传入。
组件库不提供上传后端。没有 action 或 customRequest 时,内部 beforeUpload 返回 false 以阻止向未知地址发送,但仍执行使用者提供的 beforeUpload。
ProFormUploadDragger
拖拽式上传入口,与 UploadButton 使用同一个 UploadFile[]、fileList 和无后端协议。默认槽替换整个拖拽区,drop 事件原样转发。
ProFormMoney
金额字段,modelValue 为 number | string | null。默认前缀为 ¥;顶层 prefix 或 fieldProps.prefix 可覆盖,传 false 可关闭。formatter、parser、stringMode 直接透传给 InputNumber。
ProFormSegmented
分段选择字段,共用选项请求协议,值为 string | number。没有选项来源时向基础控件传入空数组;选项的 disabled 与其他扩展字段会被保留。
与上层组件共用字段核心
独立字段与上层组件使用同一注册表和 FieldControl:
- ProTable 搜索项使用表单项模式,可编辑单元格使用裸控件模式。
- SchemaForm 保留自己的 FormItem、嵌套路径、动态插槽和组合字段,仅默认控件分支复用裸控件核心。
- EditableProTable 通过 ProTable 间接复用,不创建第三套字段映射。
本期 valueType 新增 treeSelect、slider、segmented。Captcha、UploadButton、UploadDragger 只作为独立组件提供,不映射为 valueType,也不内置后端。