FormModel表单 - 图1

FormModel 表单 (支持 v-model 检验)(版本:1.5.0+)

具有数据收集、校验和提交功能的表单,包含复选框、单选框、输入框、下拉选择框等元素。

何时使用

  • 需要对输入的数据类型进行校验时。

表单

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

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

表单域

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

这里我们封装了表单域 <FormModel.Item />

组件注册

  1. import { FormModel } from 'ant-design-vue';
  2. Vue.use(FormModel);

代码演示

Activity name

Activity zone

please select your zone

FormModel表单 - 图2

Activity time

FormModel表单 - 图3

Instant delivery

Activity type

Online Promotion Offline

Resources

Sponsor Venue

Activity form

CreateCancel

典型表单

Form 组件中,每一个表单域由一个 FormItem 组件构成,表单域中可以放置各种类型的表单控件,比如输入框、选择器、开关、单选框、多选框等。

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

FormModel表单 - 图4

FormModel表单 - 图5

Log in

内联登录栏

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

  1. <template>
  2. <a-form-model layout="inline" :model="formInline" @submit="handleSubmit" @submit.native.prevent>
  3. <a-form-model-item>
  4. <a-input v-model="formInline.user" placeholder="Username">
  5. <a-icon slot="prefix" type="user" style="color:rgba(0,0,0,.25)" />
  6. </a-input>
  7. </a-form-model-item>
  8. <a-form-model-item>
  9. <a-input v-model="formInline.password" type="password" placeholder="Password">
  10. <a-icon slot="prefix" type="lock" style="color:rgba(0,0,0,.25)" />
  11. </a-input>
  12. </a-form-model-item>
  13. <a-form-model-item>
  14. <a-button
  15. type="primary"
  16. html-type="submit"
  17. :disabled="formInline.user === '' || formInline.password === ''"
  18. >
  19. Log in
  20. </a-button>
  21. </a-form-model-item>
  22. </a-form-model>
  23. </template>
  24. <script>
  25. export default {
  26. data() {
  27. return {
  28. formInline: {
  29. user: '',
  30. password: '',
  31. },
  32. };
  33. },
  34. methods: {
  35. handleSubmit(e) {
  36. console.log(this.formInline);
  37. },
  38. },
  39. };
  40. </script>

Form Layout

Horizontal Vertical Inline

Field A

Field B

Submit

表单布局

表单有三种布局。

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

Activity name

Activity zone

please select your zone

FormModel表单 - 图6

Activity time

FormModel表单 - 图7

Instant delivery

Activity type

Online Promotion Offline

Resources

Sponsor Venue

Activity form

CreateReset

表单验证

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

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

Password

Confirm

Age

SubmitReset

自定义校验规则

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

  1. <template>
  2. <a-form-model ref="ruleForm" :model="ruleForm" :rules="rules" v-bind="layout">
  3. <a-form-model-item has-feedback label="Password" prop="pass">
  4. <a-input v-model="ruleForm.pass" type="password" autocomplete="off" />
  5. </a-form-model-item>
  6. <a-form-model-item has-feedback label="Confirm" prop="checkPass">
  7. <a-input v-model="ruleForm.checkPass" type="password" autocomplete="off" />
  8. </a-form-model-item>
  9. <a-form-model-item has-feedback label="Age" prop="age">
  10. <a-input v-model.number="ruleForm.age" />
  11. </a-form-model-item>
  12. <a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
  13. <a-button type="primary" @click="submitForm('ruleForm')">
  14. Submit
  15. </a-button>
  16. <a-button style="margin-left: 10px" @click="resetForm('ruleForm')">
  17. Reset
  18. </a-button>
  19. </a-form-model-item>
  20. </a-form-model>
  21. </template>
  22. <script>
  23. export default {
  24. data() {
  25. let checkPending;
  26. let checkAge = (rule, value, callback) => {
  27. clearTimeout(checkPending);
  28. if (!value) {
  29. return callback(new Error('Please input the age'));
  30. }
  31. checkPending = setTimeout(() => {
  32. if (!Number.isInteger(value)) {
  33. callback(new Error('Please input digits'));
  34. } else {
  35. if (value < 18) {
  36. callback(new Error('Age must be greater than 18'));
  37. } else {
  38. callback();
  39. }
  40. }
  41. }, 1000);
  42. };
  43. let validatePass = (rule, value, callback) => {
  44. if (value === '') {
  45. callback(new Error('Please input the password'));
  46. } else {
  47. if (this.ruleForm.checkPass !== '') {
  48. this.$refs.ruleForm.validateField('checkPass');
  49. }
  50. callback();
  51. }
  52. };
  53. let validatePass2 = (rule, value, callback) => {
  54. if (value === '') {
  55. callback(new Error('Please input the password again'));
  56. } else if (value !== this.ruleForm.pass) {
  57. callback(new Error("Two inputs don't match!"));
  58. } else {
  59. callback();
  60. }
  61. };
  62. return {
  63. ruleForm: {
  64. pass: '',
  65. checkPass: '',
  66. age: '',
  67. },
  68. rules: {
  69. pass: [{ validator: validatePass, trigger: 'change' }],
  70. checkPass: [{ validator: validatePass2, trigger: 'change' }],
  71. age: [{ validator: checkAge, trigger: 'change' }],
  72. },
  73. layout: {
  74. labelCol: { span: 4 },
  75. wrapperCol: { span: 14 },
  76. },
  77. };
  78. },
  79. methods: {
  80. submitForm(formName) {
  81. this.$refs[formName].validate(valid => {
  82. if (valid) {
  83. alert('submit!');
  84. } else {
  85. console.log('error submit!!');
  86. return false;
  87. }
  88. });
  89. },
  90. resetForm(formName) {
  91. this.$refs[formName].resetFields();
  92. },
  93. },
  94. };
  95. </script>

FormModel表单 - 图8Add field

SubmitReset

动态增减表单项

动态增加、减少表单项。

  1. <template>
  2. <a-form-model
  3. ref="dynamicValidateForm"
  4. :model="dynamicValidateForm"
  5. v-bind="formItemLayoutWithOutLabel"
  6. >
  7. <a-form-model-item
  8. v-for="(domain, index) in dynamicValidateForm.domains"
  9. :key="domain.key"
  10. v-bind="index === 0 ? formItemLayout : {}"
  11. :label="index === 0 ? 'Domains' : ''"
  12. :prop="'domains.' + index + '.value'"
  13. :rules="{
  14. required: true,
  15. message: 'domain can not be null',
  16. trigger: 'blur',
  17. }"
  18. >
  19. <a-input
  20. v-model="domain.value"
  21. placeholder="please input domain"
  22. style="width: 60%; margin-right: 8px"
  23. />
  24. <a-icon
  25. v-if="dynamicValidateForm.domains.length > 1"
  26. class="dynamic-delete-button"
  27. type="minus-circle-o"
  28. :disabled="dynamicValidateForm.domains.length === 1"
  29. @click="removeDomain(domain)"
  30. />
  31. </a-form-model-item>
  32. <a-form-model-item v-bind="formItemLayoutWithOutLabel">
  33. <a-button type="dashed" style="width: 60%" @click="addDomain">
  34. <a-icon type="plus" /> Add field
  35. </a-button>
  36. </a-form-model-item>
  37. <a-form-model-item v-bind="formItemLayoutWithOutLabel">
  38. <a-button type="primary" html-type="submit" @click="submitForm('dynamicValidateForm')">
  39. Submit
  40. </a-button>
  41. <a-button style="margin-left: 10px" @click="resetForm('dynamicValidateForm')">
  42. Reset
  43. </a-button>
  44. </a-form-model-item>
  45. </a-form-model>
  46. </template>
  47. <script>
  48. export default {
  49. data() {
  50. return {
  51. formItemLayout: {
  52. labelCol: {
  53. xs: { span: 24 },
  54. sm: { span: 4 },
  55. },
  56. wrapperCol: {
  57. xs: { span: 24 },
  58. sm: { span: 20 },
  59. },
  60. },
  61. formItemLayoutWithOutLabel: {
  62. wrapperCol: {
  63. xs: { span: 24, offset: 0 },
  64. sm: { span: 20, offset: 4 },
  65. },
  66. },
  67. dynamicValidateForm: {
  68. domains: [],
  69. },
  70. };
  71. },
  72. methods: {
  73. submitForm(formName) {
  74. this.$refs[formName].validate(valid => {
  75. if (valid) {
  76. alert('submit!');
  77. } else {
  78. console.log('error submit!!');
  79. return false;
  80. }
  81. });
  82. },
  83. resetForm(formName) {
  84. this.$refs[formName].resetFields();
  85. },
  86. removeDomain(item) {
  87. let index = this.dynamicValidateForm.domains.indexOf(item);
  88. if (index !== -1) {
  89. this.dynamicValidateForm.domains.splice(index, 1);
  90. }
  91. },
  92. addDomain() {
  93. this.dynamicValidateForm.domains.push({
  94. value: '',
  95. key: Date.now(),
  96. });
  97. },
  98. },
  99. };
  100. </script>
  101. <style>
  102. .dynamic-delete-button {
  103. cursor: pointer;
  104. position: relative;
  105. top: 4px;
  106. font-size: 24px;
  107. color: #999;
  108. transition: all 0.3s;
  109. }
  110. .dynamic-delete-button:hover {
  111. color: #777;
  112. }
  113. .dynamic-delete-button[disabled] {
  114. cursor: not-allowed;
  115. opacity: 0.5;
  116. }
  117. </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

事件

事件名称说明回调参数
submit数据验证成功后回调事件Function(e:Event)
validate任一表单项被校验后触发被校验的表单项 prop 值,校验是否通过,错误消息(如果存在)

方法

方法名说明参数
validate对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promiseFunction(callback: Function(boolean, object))
validateField对部分表单字段进行校验的方法Function(props: array | string, callback: Function(errorMessage: string))
resetFields对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
clearValidate移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果Function(props: array | string)

Form.Item

参数说明类型默认值版本
prop表单域 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

注意:

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

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

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