Form表单 - 图1

Form 表单

高性能表单控件,自带数据域管理。包含数据录入、校验以及对应样式。 集成 @ant-design-vue/use 更加灵活的使用表单组件。

何时使用

  • 用于创建一个实体或收集信息。
  • 需要对输入的数据类型进行校验时。

表单

我们为 form 提供了以下三种排列方式:

  • 水平排列:标签和表单控件水平排列;(默认)
  • 垂直排列:标签和表单控件上下垂直排列;
  • 行内排列:表单项水平行内排列。

表单域

表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等。

代码演示

Activity name

Activity zone

please select your zone

Form表单 - 图2

Activity time

Form表单 - 图3

Instant delivery

Activity type

OnlinePromotionOffline

Resources

SponsorVenue

Activity form

CreateCancel

基本使用

基本的表单数据域控制展示,包含布局、初始化、验证、提交。

  1. <template>
  2. <a-form :model="formState" :label-col="labelCol" :wrapper-col="wrapperCol">
  3. <a-form-item label="Activity name">
  4. <a-input v-model:value="formState.name" />
  5. </a-form-item>
  6. <a-form-item label="Activity zone">
  7. <a-select v-model:value="formState.region" placeholder="please select your zone">
  8. <a-select-option value="shanghai">Zone one</a-select-option>
  9. <a-select-option value="beijing">Zone two</a-select-option>
  10. </a-select>
  11. </a-form-item>
  12. <a-form-item label="Activity time">
  13. <a-date-picker
  14. v-model:value="formState.date1"
  15. show-time
  16. type="date"
  17. placeholder="Pick a date"
  18. style="width: 100%"
  19. />
  20. </a-form-item>
  21. <a-form-item label="Instant delivery">
  22. <a-switch v-model:checked="formState.delivery" />
  23. </a-form-item>
  24. <a-form-item label="Activity type">
  25. <a-checkbox-group v-model:value="formState.type">
  26. <a-checkbox value="1" name="type">Online</a-checkbox>
  27. <a-checkbox value="2" name="type">Promotion</a-checkbox>
  28. <a-checkbox value="3" name="type">Offline</a-checkbox>
  29. </a-checkbox-group>
  30. </a-form-item>
  31. <a-form-item label="Resources">
  32. <a-radio-group v-model:value="formState.resource">
  33. <a-radio value="1">Sponsor</a-radio>
  34. <a-radio value="2">Venue</a-radio>
  35. </a-radio-group>
  36. </a-form-item>
  37. <a-form-item label="Activity form">
  38. <a-input v-model:value="formState.desc" type="textarea" />
  39. </a-form-item>
  40. <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
  41. <a-button type="primary" @click="onSubmit">Create</a-button>
  42. <a-button style="margin-left: 10px">Cancel</a-button>
  43. </a-form-item>
  44. </a-form>
  45. </template>
  46. <script lang="ts">
  47. import { Moment } from 'moment';
  48. import { defineComponent, reactive, toRaw, UnwrapRef } from 'vue';
  49. interface FormState {
  50. name: string;
  51. region: string | undefined;
  52. date1: Moment | undefined;
  53. delivery: boolean;
  54. type: string[];
  55. resource: string;
  56. desc: string;
  57. }
  58. export default defineComponent({
  59. setup() {
  60. const formState: UnwrapRef<FormState> = reactive({
  61. name: '',
  62. region: undefined,
  63. date1: undefined,
  64. delivery: false,
  65. type: [],
  66. resource: '',
  67. desc: '',
  68. });
  69. const onSubmit = () => {
  70. console.log('submit!', toRaw(formState));
  71. };
  72. return {
  73. labelCol: { span: 4 },
  74. wrapperCol: { span: 14 },
  75. formState,
  76. onSubmit,
  77. };
  78. },
  79. });
  80. </script>

Form表单 - 图4

Form表单 - 图5

Log in

内联登录栏

水平登录栏,常用在顶部导航栏中。

  1. <template>
  2. <a-form
  3. layout="inline"
  4. :model="formState"
  5. @finish="handleFinish"
  6. @finishFailed="handleFinishFailed"
  7. >
  8. <a-form-item>
  9. <a-input v-model:value="formState.user" placeholder="Username">
  10. <template #prefix><UserOutlined style="color: rgba(0, 0, 0, 0.25)" /></template>
  11. </a-input>
  12. </a-form-item>
  13. <a-form-item>
  14. <a-input v-model:value="formState.password" type="password" placeholder="Password">
  15. <template #prefix><LockOutlined style="color: rgba(0, 0, 0, 0.25)" /></template>
  16. </a-input>
  17. </a-form-item>
  18. <a-form-item>
  19. <a-button
  20. type="primary"
  21. html-type="submit"
  22. :disabled="formState.user === '' || formState.password === ''"
  23. >
  24. Log in
  25. </a-button>
  26. </a-form-item>
  27. </a-form>
  28. </template>
  29. <script lang="ts">
  30. import { UserOutlined, LockOutlined } from '@ant-design/icons-vue';
  31. import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
  32. import { defineComponent, reactive, UnwrapRef } from 'vue';
  33. interface FormState {
  34. user: string;
  35. password: string;
  36. }
  37. export default defineComponent({
  38. setup() {
  39. const formState: UnwrapRef<FormState> = reactive({
  40. user: '',
  41. password: '',
  42. });
  43. const handleFinish = (values: FormState) => {
  44. console.log(values, formState);
  45. };
  46. const handleFinishFailed = (errors: ValidateErrorEntity<FormState>) => {
  47. console.log(errors);
  48. };
  49. return {
  50. formState,
  51. handleFinish,
  52. handleFinishFailed,
  53. };
  54. },
  55. components: {
  56. UserOutlined,
  57. LockOutlined,
  58. },
  59. });
  60. </script>

Form Layout

HorizontalVerticalInline

Field A

Field B

Submit

表单布局

表单有三种布局。

  1. <template>
  2. <a-form :layout="formState.layout" :model="formState" v-bind="formItemLayout">
  3. <a-form-item label="Form Layout">
  4. <a-radio-group v-model:value="formState.layout">
  5. <a-radio-button value="horizontal">Horizontal</a-radio-button>
  6. <a-radio-button value="vertical">Vertical</a-radio-button>
  7. <a-radio-button value="inline">Inline</a-radio-button>
  8. </a-radio-group>
  9. </a-form-item>
  10. <a-form-item label="Field A">
  11. <a-input v-model:value="formState.fieldA" placeholder="input placeholder" />
  12. </a-form-item>
  13. <a-form-item label="Field B">
  14. <a-input v-model:value="formState.fieldB" placeholder="input placeholder" />
  15. </a-form-item>
  16. <a-form-item :wrapper-col="buttonItemLayout.wrapperCol">
  17. <a-button type="primary">Submit</a-button>
  18. </a-form-item>
  19. </a-form>
  20. </template>
  21. <script lang="ts">
  22. import { computed, defineComponent, reactive, UnwrapRef } from 'vue';
  23. interface FormState {
  24. layout: 'horizontal' | 'vertical' | 'inline';
  25. fieldA: string;
  26. fieldB: string;
  27. }
  28. export default defineComponent({
  29. setup() {
  30. const formState: UnwrapRef<FormState> = reactive({
  31. layout: 'horizontal',
  32. fieldA: '',
  33. fieldB: '',
  34. });
  35. const formItemLayout = computed(() => {
  36. const { layout } = formState;
  37. return layout === 'horizontal'
  38. ? {
  39. labelCol: { span: 4 },
  40. wrapperCol: { span: 14 },
  41. }
  42. : {};
  43. });
  44. const buttonItemLayout = computed(() => {
  45. const { layout } = formState;
  46. return layout === 'horizontal'
  47. ? {
  48. wrapperCol: { span: 14, offset: 4 },
  49. }
  50. : {};
  51. });
  52. return {
  53. formState,
  54. formItemLayout,
  55. buttonItemLayout,
  56. };
  57. },
  58. });
  59. </script>

Activity name

Activity zone

please select your zone

Form表单 - 图6

Activity time

Form表单 - 图7

Instant delivery

Activity type

OnlinePromotionOffline

Resources

SponsorVenue

Activity form

CreateReset

表单验证

Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 FormItemprop 属性设置为需校验的字段名即可。校验规则参见 async-validator

  1. <template>
  2. <a-form
  3. ref="formRef"
  4. :model="formState"
  5. :rules="rules"
  6. :label-col="labelCol"
  7. :wrapper-col="wrapperCol"
  8. >
  9. <a-form-item ref="name" label="Activity name" name="name">
  10. <a-input v-model:value="formState.name" />
  11. </a-form-item>
  12. <a-form-item label="Activity zone" name="region">
  13. <a-select v-model:value="formState.region" placeholder="please select your zone">
  14. <a-select-option value="shanghai">Zone one</a-select-option>
  15. <a-select-option value="beijing">Zone two</a-select-option>
  16. </a-select>
  17. </a-form-item>
  18. <a-form-item label="Activity time" required name="date1">
  19. <a-date-picker
  20. v-model:value="formState.date1"
  21. show-time
  22. type="date"
  23. placeholder="Pick a date"
  24. style="width: 100%"
  25. />
  26. </a-form-item>
  27. <a-form-item label="Instant delivery" name="delivery">
  28. <a-switch v-model:checked="formState.delivery" />
  29. </a-form-item>
  30. <a-form-item label="Activity type" name="type">
  31. <a-checkbox-group v-model:value="formState.type">
  32. <a-checkbox value="1" name="type">Online</a-checkbox>
  33. <a-checkbox value="2" name="type">Promotion</a-checkbox>
  34. <a-checkbox value="3" name="type">Offline</a-checkbox>
  35. </a-checkbox-group>
  36. </a-form-item>
  37. <a-form-item label="Resources" name="resource">
  38. <a-radio-group v-model:value="formState.resource">
  39. <a-radio value="1">Sponsor</a-radio>
  40. <a-radio value="2">Venue</a-radio>
  41. </a-radio-group>
  42. </a-form-item>
  43. <a-form-item label="Activity form" name="desc">
  44. <a-textarea v-model:value="formState.desc" />
  45. </a-form-item>
  46. <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
  47. <a-button type="primary" @click="onSubmit">Create</a-button>
  48. <a-button style="margin-left: 10px" @click="resetForm">Reset</a-button>
  49. </a-form-item>
  50. </a-form>
  51. </template>
  52. <script lang="ts">
  53. import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
  54. import { Moment } from 'moment';
  55. import { defineComponent, reactive, ref, toRaw, UnwrapRef } from 'vue';
  56. interface FormState {
  57. name: string;
  58. region: string | undefined;
  59. date1: Moment | undefined;
  60. delivery: boolean;
  61. type: string[];
  62. resource: string;
  63. desc: string;
  64. }
  65. export default defineComponent({
  66. setup() {
  67. const formRef = ref();
  68. const formState: UnwrapRef<FormState> = reactive({
  69. name: '',
  70. region: undefined,
  71. date1: undefined,
  72. delivery: false,
  73. type: [],
  74. resource: '',
  75. desc: '',
  76. });
  77. const rules = {
  78. name: [
  79. { required: true, message: 'Please input Activity name', trigger: 'blur' },
  80. { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
  81. ],
  82. region: [{ required: true, message: 'Please select Activity zone', trigger: 'change' }],
  83. date1: [{ required: true, message: 'Please pick a date', trigger: 'change', type: 'object' }],
  84. type: [
  85. {
  86. type: 'array',
  87. required: true,
  88. message: 'Please select at least one activity type',
  89. trigger: 'change',
  90. },
  91. ],
  92. resource: [{ required: true, message: 'Please select activity resource', trigger: 'change' }],
  93. desc: [{ required: true, message: 'Please input activity form', trigger: 'blur' }],
  94. };
  95. const onSubmit = () => {
  96. formRef.value
  97. .validate()
  98. .then(() => {
  99. console.log('values', formState, toRaw(formState));
  100. })
  101. .catch((error: ValidateErrorEntity<FormState>) => {
  102. console.log('error', error);
  103. });
  104. };
  105. const resetForm = () => {
  106. formRef.value.ruleformState.resetFields();
  107. };
  108. return {
  109. formRef,
  110. labelCol: { span: 4 },
  111. wrapperCol: { span: 14 },
  112. other: '',
  113. formState,
  114. rules,
  115. onSubmit,
  116. resetForm,
  117. };
  118. },
  119. });
  120. </script>

Password

Confirm

Age

Form表单 - 图8Form表单 - 图9

SubmitReset

自定义校验规则

这个例子中展示了如何使用自定义验证规则来完成密码的二次验证。本例还使用 has-feedback 属性为输入框添加了表示校验结果的反馈图标。 更多高级用法可参考 async-validator

  1. <template>
  2. <a-form
  3. name="custom-validation"
  4. ref="formRef"
  5. :model="formState"
  6. :rules="rules"
  7. v-bind="layout"
  8. @finish="handleFinish"
  9. @finishFailed="handleFinishFailed"
  10. >
  11. <a-form-item required has-feedback label="Password" name="pass">
  12. <a-input v-model:value="formState.pass" type="password" autocomplete="off" />
  13. </a-form-item>
  14. <a-form-item has-feedback label="Confirm" name="checkPass">
  15. <a-input v-model:value="formState.checkPass" type="password" autocomplete="off" />
  16. </a-form-item>
  17. <a-form-item has-feedback label="Age" name="age">
  18. <a-input-number v-model:value="formState.age" />
  19. </a-form-item>
  20. <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
  21. <a-button type="primary" html-type="submit">Submit</a-button>
  22. <a-button style="margin-left: 10px" @click="resetForm">Reset</a-button>
  23. </a-form-item>
  24. </a-form>
  25. </template>
  26. <script lang="ts">
  27. import { RuleObject, ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
  28. import { defineComponent, reactive, ref, UnwrapRef } from 'vue';
  29. interface FormState {
  30. pass: string;
  31. checkPass: string;
  32. age: number | undefined;
  33. }
  34. export default defineComponent({
  35. setup() {
  36. const formRef = ref();
  37. const formState: UnwrapRef<FormState> = reactive({
  38. pass: '',
  39. checkPass: '',
  40. age: undefined,
  41. });
  42. let checkAge = async (rule: RuleObject, value: number) => {
  43. if (!value) {
  44. return Promise.reject('Please input the age');
  45. }
  46. if (!Number.isInteger(value)) {
  47. return Promise.reject('Please input digits');
  48. } else {
  49. if (value < 18) {
  50. return Promise.reject('Age must be greater than 18');
  51. } else {
  52. return Promise.resolve();
  53. }
  54. }
  55. };
  56. let validatePass = async (rule: RuleObject, value: string) => {
  57. if (value === '') {
  58. return Promise.reject('Please input the password');
  59. } else {
  60. if (formState.checkPass !== '') {
  61. formRef.value.validateField('checkPass');
  62. }
  63. return Promise.resolve();
  64. }
  65. };
  66. let validatePass2 = async (rule: RuleObject, value: string) => {
  67. if (value === '') {
  68. return Promise.reject('Please input the password again');
  69. } else if (value !== formState.pass) {
  70. return Promise.reject("Two inputs don't match!");
  71. } else {
  72. return Promise.resolve();
  73. }
  74. };
  75. const rules = {
  76. pass: [{ validator: validatePass, trigger: 'change' }],
  77. checkPass: [{ validator: validatePass2, trigger: 'change' }],
  78. age: [{ validator: checkAge, trigger: 'change' }],
  79. };
  80. const layout = {
  81. labelCol: { span: 4 },
  82. wrapperCol: { span: 14 },
  83. };
  84. const handleFinish = (values: FormState) => {
  85. console.log(values, formState);
  86. };
  87. const handleFinishFailed = (errors: ValidateErrorEntity<FormState>) => {
  88. console.log(errors);
  89. };
  90. const resetForm = () => {
  91. formRef.value.resetFields();
  92. };
  93. return {
  94. formState,
  95. formRef,
  96. rules,
  97. layout,
  98. handleFinishFailed,
  99. handleFinish,
  100. resetForm,
  101. };
  102. },
  103. });
  104. </script>

Form表单 - 图10Add field

SubmitReset

动态增减表单项

动态增加、减少表单项。

  1. <template>
  2. <a-form ref="formRef" :model="dynamicValidateForm" v-bind="formItemLayoutWithOutLabel">
  3. <a-form-item
  4. v-for="(domain, index) in dynamicValidateForm.domains"
  5. :key="domain.key"
  6. v-bind="index === 0 ? formItemLayout : {}"
  7. :label="index === 0 ? 'Domains' : ''"
  8. :name="['domains', index, 'value']"
  9. :rules="{
  10. required: true,
  11. message: 'domain can not be null',
  12. trigger: 'change',
  13. }"
  14. >
  15. <a-input
  16. v-model:value="domain.value"
  17. placeholder="please input domain"
  18. style="width: 60%; margin-right: 8px"
  19. />
  20. <MinusCircleOutlined
  21. v-if="dynamicValidateForm.domains.length > 1"
  22. class="dynamic-delete-button"
  23. :disabled="dynamicValidateForm.domains.length === 1"
  24. @click="removeDomain(domain)"
  25. />
  26. </a-form-item>
  27. <a-form-item v-bind="formItemLayoutWithOutLabel">
  28. <a-button type="dashed" style="width: 60%" @click="addDomain">
  29. <PlusOutlined />
  30. Add field
  31. </a-button>
  32. </a-form-item>
  33. <a-form-item v-bind="formItemLayoutWithOutLabel">
  34. <a-button type="primary" html-type="submit" @click="submitForm">Submit</a-button>
  35. <a-button style="margin-left: 10px" @click="resetForm">Reset</a-button>
  36. </a-form-item>
  37. </a-form>
  38. </template>
  39. <script lang="ts">
  40. import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons-vue';
  41. import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
  42. import { defineComponent, reactive, ref, UnwrapRef } from 'vue';
  43. interface Domain {
  44. value: string;
  45. key: number;
  46. }
  47. export default defineComponent({
  48. setup() {
  49. const formRef = ref();
  50. const formItemLayout = {
  51. labelCol: {
  52. xs: { span: 24 },
  53. sm: { span: 4 },
  54. },
  55. wrapperCol: {
  56. xs: { span: 24 },
  57. sm: { span: 20 },
  58. },
  59. };
  60. const formItemLayoutWithOutLabel = {
  61. wrapperCol: {
  62. xs: { span: 24, offset: 0 },
  63. sm: { span: 20, offset: 4 },
  64. },
  65. };
  66. const dynamicValidateForm: UnwrapRef<{ domains: Domain[] }> = reactive({
  67. domains: [],
  68. });
  69. const submitForm = () => {
  70. formRef.value
  71. .validate()
  72. .then(() => {
  73. console.log('values', dynamicValidateForm.domains);
  74. })
  75. .catch((error: ValidateErrorEntity<any>) => {
  76. console.log('error', error);
  77. });
  78. };
  79. const resetForm = () => {
  80. formRef.value.resetFields();
  81. };
  82. const removeDomain = (item: Domain) => {
  83. let index = dynamicValidateForm.domains.indexOf(item);
  84. if (index !== -1) {
  85. dynamicValidateForm.domains.splice(index, 1);
  86. }
  87. };
  88. const addDomain = () => {
  89. dynamicValidateForm.domains.push({
  90. value: '',
  91. key: Date.now(),
  92. });
  93. };
  94. return {
  95. formRef,
  96. formItemLayout,
  97. formItemLayoutWithOutLabel,
  98. dynamicValidateForm,
  99. submitForm,
  100. resetForm,
  101. removeDomain,
  102. addDomain,
  103. };
  104. },
  105. components: {
  106. MinusCircleOutlined,
  107. PlusOutlined,
  108. },
  109. });
  110. </script>
  111. <style>
  112. .dynamic-delete-button {
  113. cursor: pointer;
  114. position: relative;
  115. top: 4px;
  116. font-size: 24px;
  117. color: #999;
  118. transition: all 0.3s;
  119. }
  120. .dynamic-delete-button:hover {
  121. color: #777;
  122. }
  123. .dynamic-delete-button[disabled] {
  124. cursor: not-allowed;
  125. opacity: 0.5;
  126. }
  127. </style>

Activity name

Activity zone

please select your zone

Form表单 - 图11

Activity type

OnlinePromotionOffline

CreateReset

useForm 基本表单

集成 @ant-design-vue/use 更加灵活的使用表单组件。useForm 提供表单校验逻辑和状态。

  1. <template>
  2. <a-form :label-col="labelCol" :wrapper-col="wrapperCol">
  3. <a-form-item label="Activity name" v-bind="validateInfos.name">
  4. <a-input v-model:value="modelRef.name" />
  5. </a-form-item>
  6. <a-form-item label="Activity zone" v-bind="validateInfos.region">
  7. <a-select v-model:value="modelRef.region" placeholder="please select your zone">
  8. <a-select-option value="shanghai">Zone one</a-select-option>
  9. <a-select-option value="beijing">Zone two</a-select-option>
  10. </a-select>
  11. </a-form-item>
  12. <a-form-item label="Activity type" v-bind="validateInfos.type">
  13. <a-checkbox-group v-model:value="modelRef.type">
  14. <a-checkbox value="1" name="type">Online</a-checkbox>
  15. <a-checkbox value="2" name="type">Promotion</a-checkbox>
  16. <a-checkbox value="3" name="type">Offline</a-checkbox>
  17. </a-checkbox-group>
  18. </a-form-item>
  19. <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
  20. <a-button type="primary" @click.prevent="onSubmit">Create</a-button>
  21. <a-button style="margin-left: 10px" @click="resetFields">Reset</a-button>
  22. </a-form-item>
  23. </a-form>
  24. </template>
  25. <script lang="ts">
  26. import { defineComponent, reactive, toRaw } from 'vue';
  27. import { useForm } from '@ant-design-vue/use';
  28. export default defineComponent({
  29. setup() {
  30. const modelRef = reactive({
  31. name: '',
  32. region: undefined,
  33. type: [],
  34. });
  35. const rulesRef = reactive({
  36. name: [
  37. {
  38. required: true,
  39. message: 'Please input name',
  40. },
  41. ],
  42. region: [
  43. {
  44. required: true,
  45. message: 'Please select region',
  46. },
  47. ],
  48. type: [
  49. {
  50. required: true,
  51. message: 'Please select type',
  52. type: 'array',
  53. },
  54. ],
  55. });
  56. const { resetFields, validate, validateInfos } = useForm(modelRef, rulesRef);
  57. const onSubmit = () => {
  58. validate()
  59. .then(() => {
  60. console.log(toRaw(modelRef));
  61. })
  62. .catch(err => {
  63. console.log('error', err);
  64. });
  65. };
  66. return {
  67. labelCol: { span: 4 },
  68. wrapperCol: { span: 14 },
  69. validateInfos,
  70. resetFields,
  71. modelRef,
  72. onSubmit,
  73. };
  74. },
  75. });
  76. </script>

Activity name

Sub name

CreateReset

useForm 嵌套表单

集成 @ant-design-vue/use 更加灵活的使用表单组件。使用点字符串拼接进行嵌套数据校验。

  1. <template>
  2. <a-form :label-col="labelCol" :wrapper-col="wrapperCol">
  3. <a-form-item label="Activity name" v-bind="validateInfos.name">
  4. <a-input v-model:value="modelRef.name" />
  5. </a-form-item>
  6. <a-form-item label="Sub name" v-bind="validateInfos['sub.name']">
  7. <a-input v-model:value="modelRef.sub.name" />
  8. </a-form-item>
  9. <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
  10. <a-button type="primary" @click.prevent="onSubmit">Create</a-button>
  11. <a-button style="margin-left: 10px" @click="reset">Reset</a-button>
  12. </a-form-item>
  13. </a-form>
  14. </template>
  15. <script lang="ts">
  16. import { defineComponent, reactive, toRaw } from 'vue';
  17. import { useForm } from '@ant-design-vue/use';
  18. export default defineComponent({
  19. setup() {
  20. const modelRef = reactive({
  21. name: '',
  22. sub: {
  23. name: '',
  24. },
  25. });
  26. const { resetFields, validate, validateInfos } = useForm(
  27. modelRef,
  28. reactive({
  29. name: [
  30. {
  31. required: true,
  32. message: 'Please input name',
  33. },
  34. ],
  35. 'sub.name': [
  36. {
  37. required: true,
  38. message: 'Please input sub name',
  39. },
  40. ],
  41. }),
  42. );
  43. const onSubmit = () => {
  44. validate()
  45. .then(res => {
  46. console.log(res, toRaw(modelRef));
  47. })
  48. .catch(err => {
  49. console.log('error', err);
  50. });
  51. };
  52. const reset = () => {
  53. resetFields();
  54. };
  55. return {
  56. labelCol: { span: 4 },
  57. wrapperCol: { span: 14 },
  58. validateInfos,
  59. reset,
  60. modelRef,
  61. onSubmit,
  62. };
  63. },
  64. });
  65. </script>

Activity name

Activity zone

please select your zone

Form表单 - 图12

CreateReset

useForm 自定义触发时机

集成 @ant-design-vue/use 更加灵活的使用表单组件。useForm 自定义触发校验时机

  1. <template>
  2. <a-form :label-col="labelCol" :wrapper-col="wrapperCol">
  3. <a-form-item label="Activity name" v-bind="validateInfos.name">
  4. <a-input
  5. v-model:value="modelRef.name"
  6. @blur="validate('name', { trigger: 'blur' }).catch(() => {})"
  7. />
  8. </a-form-item>
  9. <a-form-item label="Activity zone" v-bind="validateInfos.region">
  10. <a-select v-model:value="modelRef.region" placeholder="please select your zone">
  11. <a-select-option value="shanghai">Zone one</a-select-option>
  12. <a-select-option value="beijing">Zone two</a-select-option>
  13. </a-select>
  14. </a-form-item>
  15. <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
  16. <a-button type="primary" @click.prevent="onSubmit">Create</a-button>
  17. <a-button style="margin-left: 10px" @click="resetFields">Reset</a-button>
  18. </a-form-item>
  19. </a-form>
  20. </template>
  21. <script lang="ts">
  22. import { defineComponent, reactive, toRaw } from 'vue';
  23. import { useForm } from '@ant-design-vue/use';
  24. export default defineComponent({
  25. setup() {
  26. const modelRef = reactive({
  27. name: '',
  28. region: undefined,
  29. });
  30. const rulesRef = reactive({
  31. name: [
  32. {
  33. required: true,
  34. message: 'Please input Activity name',
  35. },
  36. {
  37. min: 3,
  38. max: 5,
  39. message: 'Length should be 3 to 5',
  40. trigger: 'blur',
  41. },
  42. ],
  43. region: [
  44. {
  45. required: true,
  46. message: 'Please select region',
  47. },
  48. ],
  49. });
  50. const { resetFields, validate, validateInfos } = useForm(modelRef, rulesRef);
  51. const onSubmit = () => {
  52. validate()
  53. .then(() => {
  54. console.log(toRaw(modelRef));
  55. })
  56. .catch(err => {
  57. console.log('error', err);
  58. });
  59. };
  60. return {
  61. labelCol: { span: 4 },
  62. wrapperCol: { span: 14 },
  63. validate,
  64. validateInfos,
  65. resetFields,
  66. modelRef,
  67. onSubmit,
  68. };
  69. },
  70. });
  71. </script>

Activity name

Activity zone

please select your zone

Form表单 - 图13

Activity type

OnlinePromotionOffline

CreateReset

useForm 合并错误信息

集成 @ant-design-vue/use 更加灵活的使用表单组件。useForm 合并展示表单校验信息。

  1. <template>
  2. <a-form :label-col="labelCol" :wrapper-col="wrapperCol">
  3. <a-form-item label="Activity name" required>
  4. <a-input v-model:value="modelRef.name" />
  5. </a-form-item>
  6. <a-form-item label="Activity zone" required>
  7. <a-select v-model:value="modelRef.region" placeholder="please select your zone">
  8. <a-select-option value="shanghai">Zone one</a-select-option>
  9. <a-select-option value="beijing">Zone two</a-select-option>
  10. </a-select>
  11. </a-form-item>
  12. <a-form-item label="Activity type" required>
  13. <a-checkbox-group v-model:value="modelRef.type">
  14. <a-checkbox value="1" name="type">Online</a-checkbox>
  15. <a-checkbox value="2" name="type">Promotion</a-checkbox>
  16. <a-checkbox value="3" name="type">Offline</a-checkbox>
  17. </a-checkbox-group>
  18. </a-form-item>
  19. <a-form-item class="error-infos" :wrapper-col="{ span: 14, offset: 4 }" v-bind="errorInfos">
  20. <a-button type="primary" @click.prevent="onSubmit">Create</a-button>
  21. <a-button style="margin-left: 10px" @click="resetFields">Reset</a-button>
  22. </a-form-item>
  23. </a-form>
  24. </template>
  25. <script lang="ts">
  26. import { reactive, toRaw, computed, defineComponent } from 'vue';
  27. import { useForm } from '@ant-design-vue/use';
  28. import { toArray } from 'lodash-es';
  29. export default defineComponent({
  30. setup() {
  31. const modelRef = reactive({
  32. name: '',
  33. region: undefined,
  34. type: [],
  35. });
  36. const rulesRef = reactive({
  37. name: [
  38. {
  39. required: true,
  40. message: 'Please input name',
  41. },
  42. ],
  43. region: [
  44. {
  45. required: true,
  46. message: 'Please select region',
  47. },
  48. ],
  49. type: [
  50. {
  51. required: true,
  52. message: 'Please select type',
  53. type: 'array',
  54. },
  55. ],
  56. });
  57. const { resetFields, validate, validateInfos, mergeValidateInfo } = useForm(modelRef, rulesRef);
  58. const onSubmit = () => {
  59. validate()
  60. .then(() => {
  61. console.log(toRaw(modelRef));
  62. })
  63. .catch(err => {
  64. console.log('error', err);
  65. });
  66. };
  67. const errorInfos = computed(() => {
  68. return mergeValidateInfo(toArray(validateInfos));
  69. });
  70. return {
  71. labelCol: { span: 4 },
  72. wrapperCol: { span: 14 },
  73. validateInfos,
  74. resetFields,
  75. modelRef,
  76. onSubmit,
  77. errorInfos,
  78. };
  79. },
  80. });
  81. </script>
  82. <style scoped>
  83. .error-infos :deep(.ant-form-explain) {
  84. white-space: pre-line;
  85. }
  86. </style>

API

Form

参数说明类型默认值版本
model表单数据对象object
rules表单验证规则object
hideRequiredMark隐藏所有表单项的必选标记Booleanfalse
labelAlignlabel 标签的文本对齐方式‘left’ | ‘right’‘right’
layout表单布局‘horizontal’|’vertical’|’inline’‘horizontal’
labelCollabel 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12}sm: {span: 3, offset: 12}object
wrapperCol需要为输入控件设置布局样式时,使用该属性,用法同 labelColobject
colon配置 Form.Item 的 colon 的默认值 (只有在属性 layout 为 horizontal 时有效)booleantrue
validateOnRuleChange是否在 rules 属性改变后立即触发一次验证booleantrue
scrollToFirstError提交失败自动滚动到第一个错误字段booleanfalse2.0.0
name表单名称,会作为表单字段 id 前缀使用string-2.0.0
validateTrigger统一设置字段校验规则string | string[]change2.0.0

事件

事件名称说明回调参数版本
submit数据验证成功后回调事件Function(e:Event)
validate任一表单项被校验后触发被校验的表单项 name 值,校验是否通过,错误消息(如果存在)
finish提交表单且数据验证成功后回调事件function(values)-
finishFailed提交表单且数据验证失败后回调事件function({ values, errorFields, outOfDate })-

方法

方法名说明参数
validate触发表单验证, 同 validateFields(nameList?: NamePath[]) => Promise
validateFields触发表单验证(nameList?: NamePath[]) => Promise
scrollToField滚动到对应字段位置(name: NamePath, options: [ScrollOptions]) => void
resetFields对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
clearValidate移除表单项的校验结果。传入待移除的表单项的 name 属性或者 name 组成的数组,如不传则移除整个表单的校验结果Function(name: array | string)

Form.Item

参数说明类型默认值版本
name表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的string
rules表单验证规则object | array
autoLink是否自动关联表单域,对于大部分情况都可以使用自动关联,如果不满足自动关联的条件,可以手动关联,参见下方注意事项booleantrue
colon配合 label 属性使用,表示是否显示 label 后面的冒号booleantrue
extra额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。string|slot
hasFeedback配合 validateStatus 属性使用,展示校验状态图标,建议只配合 Input 组件使用booleanfalse
help提示信息,如不设置,则会根据校验规则自动生成string|slot
htmlFor设置子元素 label htmlFor 属性string
labellabel 标签的文本string|slot
labelCollabel 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12}sm: {span: 3, offset: 12}object
labelAlign标签文本对齐方式‘left’ | ‘right’‘right’
required是否必填,如不设置,则会根据校验规则自动生成booleanfalse
validateStatus校验状态,如不设置,则会根据校验规则自动生成,可选:’success’ ‘warning’ ‘error’ ‘validating’string
wrapperCol需要为输入控件设置布局样式时,使用该属性,用法同 labelColobject
validateFirst当某一规则校验不通过时,是否停止剩下的规则的校验。booleanfalse2.0.0
validateTrigger设置字段校验的时机string | string[]change2.0.0

注意:

Form.Item 会对唯一子元素进行劫持,并监听 blurchange 事件,来达到自动校验的目的,所以请确保表单域没有其它元素包裹。如果有多个子元素,将只会监听第一个子元素的变化。

如果要监听的表单域不满足自动监听的条件,可以通过如下方式关联表单域:

  1. <a-form-item name="form.name" ref="name" :autoLink="false">
  2. <a-input v-model:value="other" />
  3. <span>hahha</span>
  4. <div>
  5. <a-input
  6. v-model:value="form.name"
  7. @blur="() => {$refs.name.onFieldBlur()}"
  8. @change="() => {$refs.name.onFieldChange()}"
  9. />
  10. </div>
  11. </a-form-item>

校验规则

参数说明类型默认值
trigger校验触发的时机‘blur’ | ‘change’ | [‘change’, ‘blur’]-
enum枚举类型string-
len字段长度number-
max最大长度number-
message校验文案string-
min最小长度number-
pattern正则表达式校验RegExp-
required是否必选booleanfalse
transform校验前转换字段值function(value) => transformedValue:any-
type内建校验类型,可选项string‘string’
validator自定义校验(注意,callback 必须被调用function(rule, value, callback)-
whitespace必选时,空格是否会被视为错误booleanfalse

更多高级用法可研究 async-validator