Form 表单

概述

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

注意:非 template/render 模式下,需使用 i-form

W3C 标准中有如下规定
When there is only one single-line text input field in a form, the user agent should accept Enter in that field as a request to submit the form.

即:当一个 form 元素中只有一个输入框时,在该输入框中按下回车应提交该表单。如果希望阻止这一默认行为,可以在 <Form> 标签上添加 @submit.native.prevent

代码示例

Form 表单 - 图1

行内表单

设置属性 inline,表单元素可以水平排列。

  1. <template>
  2. <Form ref="formInline" :model="formInline" :rules="ruleInline" inline>
  3. <FormItem prop="user">
  4. <Input type="text" v-model="formInline.user" placeholder="Username">
  5. <Icon type="ios-person-outline" slot="prepend"></Icon>
  6. </Input>
  7. </FormItem>
  8. <FormItem prop="password">
  9. <Input type="password" v-model="formInline.password" placeholder="Password">
  10. <Icon type="ios-lock-outline" slot="prepend"></Icon>
  11. </Input>
  12. </FormItem>
  13. <FormItem>
  14. <Button type="primary" @click="handleSubmit('formInline')">Signin</Button>
  15. </FormItem>
  16. </Form>
  17. </template>
  18. <script>
  19. export default {
  20. data () {
  21. return {
  22. formInline: {
  23. user: '',
  24. password: ''
  25. },
  26. ruleInline: {
  27. user: [
  28. { required: true, message: 'Please fill in the user name', trigger: 'blur' }
  29. ],
  30. password: [
  31. { required: true, message: 'Please fill in the password.', trigger: 'blur' },
  32. { type: 'string', min: 6, message: 'The password length cannot be less than 6 bits', trigger: 'blur' }
  33. ]
  34. }
  35. }
  36. },
  37. methods: {
  38. handleSubmit(name) {
  39. this.$refs[name].validate((valid) => {
  40. if (valid) {
  41. this.$Message.success('Success!');
  42. } else {
  43. this.$Message.error('Fail!');
  44. }
  45. })
  46. }
  47. }
  48. }
  49. </script>

Form 表单 - 图2

表单控件

Form 内,每个表单域由 FormItem 组成,可包含的控件有:Input、Radio、Checkbox、Switch、Select、Slider、DatePicker、TimePicker、Cascader、Transfer、InputNumber、Rate、Upload、AutoComplete、ColorPicker。

FormItem 设置属性 label 可以显示表单域的标签,需要给 Form 设置 label-width

FormItem 设置属性 label-for 可以指定原生的 label 标签的 for 属性,配合设置控件的 element-id 属性,可以点击 label 时聚焦控件。

  1. <template>
  2. <Form :model="formItem" :label-width="80">
  3. <FormItem label="Input">
  4. <Input v-model="formItem.input" placeholder="Enter something..."></Input>
  5. </FormItem>
  6. <FormItem label="Select">
  7. <Select v-model="formItem.select">
  8. <Option value="beijing">New York</Option>
  9. <Option value="shanghai">London</Option>
  10. <Option value="shenzhen">Sydney</Option>
  11. </Select>
  12. </FormItem>
  13. <FormItem label="DatePicker">
  14. <Row>
  15. <Col span="11">
  16. <DatePicker type="date" placeholder="Select date" v-model="formItem.date"></DatePicker>
  17. </Col>
  18. <Col span="2" style="text-align: center">-</Col>
  19. <Col span="11">
  20. <TimePicker type="time" placeholder="Select time" v-model="formItem.time"></TimePicker>
  21. </Col>
  22. </Row>
  23. </FormItem>
  24. <FormItem label="Radio">
  25. <RadioGroup v-model="formItem.radio">
  26. <Radio label="male">Male</Radio>
  27. <Radio label="female">Female</Radio>
  28. </RadioGroup>
  29. </FormItem>
  30. <FormItem label="Checkbox">
  31. <CheckboxGroup v-model="formItem.checkbox">
  32. <Checkbox label="Eat"></Checkbox>
  33. <Checkbox label="Sleep"></Checkbox>
  34. <Checkbox label="Run"></Checkbox>
  35. <Checkbox label="Movie"></Checkbox>
  36. </CheckboxGroup>
  37. </FormItem>
  38. <FormItem label="Switch">
  39. <i-switch v-model="formItem.switch" size="large">
  40. <span slot="open">On</span>
  41. <span slot="close">Off</span>
  42. </i-switch>
  43. </FormItem>
  44. <FormItem label="Slider">
  45. <Slider v-model="formItem.slider" range></Slider>
  46. </FormItem>
  47. <FormItem label="Text">
  48. <Input v-model="formItem.textarea" type="textarea" :autosize="{minRows: 2,maxRows: 5}" placeholder="Enter something..."></Input>
  49. </FormItem>
  50. <FormItem>
  51. <Button type="primary">Submit</Button>
  52. <Button style="margin-left: 8px">Cancel</Button>
  53. </FormItem>
  54. </Form>
  55. </template>
  56. <script>
  57. export default {
  58. data () {
  59. return {
  60. formItem: {
  61. input: '',
  62. select: '',
  63. radio: 'male',
  64. checkbox: [],
  65. switch: true,
  66. date: '',
  67. time: '',
  68. slider: [20, 50],
  69. textarea: ''
  70. }
  71. }
  72. }
  73. }
  74. </script>

Form 表单 - 图3

对齐方式

设置属性 label-position,可以改变表单域标签的位置,left 为左对齐,right 为右对齐,top 会置于表单域顶部。

  1. <template>
  2. <Form :model="formLeft" label-position="left" :label-width="100">
  3. <FormItem label="Title">
  4. <Input v-model="formLeft.input1"></Input>
  5. </FormItem>
  6. <FormItem label="Title name">
  7. <Input v-model="formLeft.input2"></Input>
  8. </FormItem>
  9. <FormItem label="Aligned title">
  10. <Input v-model="formLeft.input3"></Input>
  11. </FormItem>
  12. </Form>
  13. <Form :model="formRight" label-position="right" :label-width="100">
  14. <FormItem label="Title">
  15. <Input v-model="formRight.input1"></Input>
  16. </FormItem>
  17. <FormItem label="Title name">
  18. <Input v-model="formRight.input2"></Input>
  19. </FormItem>
  20. <FormItem label="Aligned title">
  21. <Input v-model="formRight.input3"></Input>
  22. </FormItem>
  23. </Form>
  24. <Form :model="formTop" label-position="top">
  25. <FormItem label="Title">
  26. <Input v-model="formTop.input1"></Input>
  27. </FormItem>
  28. <FormItem label="Title name">
  29. <Input v-model="formTop.input2"></Input>
  30. </FormItem>
  31. <FormItem label="Aligned title">
  32. <Input v-model="formTop.input3"></Input>
  33. </FormItem>
  34. </Form>
  35. </template>
  36. <script>
  37. export default {
  38. data () {
  39. return {
  40. formLeft: {
  41. input1: '',
  42. input2: '',
  43. input3: ''
  44. },
  45. formRight: {
  46. input1: '',
  47. input2: '',
  48. input3: ''
  49. },
  50. formTop: {
  51. input1: '',
  52. input2: '',
  53. input3: ''
  54. }
  55. }
  56. }
  57. }
  58. </script>

Form 表单 - 图4

表单验证

Form 组件基于 async-validator 实现的数据验证,给 Form 设置属性 rules,同时给需要验证的 FormItem 设置属性 prop 指向对应字段即可。

完整的验证规则请参照开源项目 async-validator。

验证方法也支持 Promise。

  1. <template>
  2. <Form ref="formValidate" :model="formValidate" :rules="ruleValidate" :label-width="80">
  3. <FormItem label="Name" prop="name">
  4. <Input v-model="formValidate.name" placeholder="Enter your name"></Input>
  5. </FormItem>
  6. <FormItem label="E-mail" prop="mail">
  7. <Input v-model="formValidate.mail" placeholder="Enter your e-mail"></Input>
  8. </FormItem>
  9. <FormItem label="City" prop="city">
  10. <Select v-model="formValidate.city" placeholder="Select your city">
  11. <Option value="beijing">New York</Option>
  12. <Option value="shanghai">London</Option>
  13. <Option value="shenzhen">Sydney</Option>
  14. </Select>
  15. </FormItem>
  16. <FormItem label="Date">
  17. <Row>
  18. <Col span="11">
  19. <FormItem prop="date">
  20. <DatePicker type="date" placeholder="Select date" v-model="formValidate.date"></DatePicker>
  21. </FormItem>
  22. </Col>
  23. <Col span="2" style="text-align: center">-</Col>
  24. <Col span="11">
  25. <FormItem prop="time">
  26. <TimePicker type="time" placeholder="Select time" v-model="formValidate.time"></TimePicker>
  27. </FormItem>
  28. </Col>
  29. </Row>
  30. </FormItem>
  31. <FormItem label="Gender" prop="gender">
  32. <RadioGroup v-model="formValidate.gender">
  33. <Radio label="male">Male</Radio>
  34. <Radio label="female">Female</Radio>
  35. </RadioGroup>
  36. </FormItem>
  37. <FormItem label="Hobby" prop="interest">
  38. <CheckboxGroup v-model="formValidate.interest">
  39. <Checkbox label="Eat"></Checkbox>
  40. <Checkbox label="Sleep"></Checkbox>
  41. <Checkbox label="Run"></Checkbox>
  42. <Checkbox label="Movie"></Checkbox>
  43. </CheckboxGroup>
  44. </FormItem>
  45. <FormItem label="Desc" prop="desc">
  46. <Input v-model="formValidate.desc" type="textarea" :autosize="{minRows: 2,maxRows: 5}" placeholder="Enter something..."></Input>
  47. </FormItem>
  48. <FormItem>
  49. <Button type="primary" @click="handleSubmit('formValidate')">Submit</Button>
  50. <Button @click="handleReset('formValidate')" style="margin-left: 8px">Reset</Button>
  51. </FormItem>
  52. </Form>
  53. </template>
  54. <script>
  55. export default {
  56. data () {
  57. return {
  58. formValidate: {
  59. name: '',
  60. mail: '',
  61. city: '',
  62. gender: '',
  63. interest: [],
  64. date: '',
  65. time: '',
  66. desc: ''
  67. },
  68. ruleValidate: {
  69. name: [
  70. { required: true, message: 'The name cannot be empty', trigger: 'blur' }
  71. ],
  72. mail: [
  73. { required: true, message: 'Mailbox cannot be empty', trigger: 'blur' },
  74. { type: 'email', message: 'Incorrect email format', trigger: 'blur' }
  75. ],
  76. city: [
  77. { required: true, message: 'Please select the city', trigger: 'change' }
  78. ],
  79. gender: [
  80. { required: true, message: 'Please select gender', trigger: 'change' }
  81. ],
  82. interest: [
  83. { required: true, type: 'array', min: 1, message: 'Choose at least one hobby', trigger: 'change' },
  84. { type: 'array', max: 2, message: 'Choose two hobbies at best', trigger: 'change' }
  85. ],
  86. date: [
  87. { required: true, type: 'date', message: 'Please select the date', trigger: 'change' }
  88. ],
  89. time: [
  90. { required: true, type: 'string', message: 'Please select time', trigger: 'change' }
  91. ],
  92. desc: [
  93. { required: true, message: 'Please enter a personal introduction', trigger: 'blur' },
  94. { type: 'string', min: 20, message: 'Introduce no less than 20 words', trigger: 'blur' }
  95. ]
  96. }
  97. }
  98. },
  99. methods: {
  100. handleSubmit (name) {
  101. this.$refs[name].validate((valid) => {
  102. if (valid) {
  103. this.$Message.success('Success!');
  104. } else {
  105. this.$Message.error('Fail!');
  106. }
  107. })
  108. },
  109. handleReset (name) {
  110. this.$refs[name].resetFields();
  111. }
  112. }
  113. }
  114. </script>

Form 表单 - 图5

自定义验证

可以完全自定义验证规则来完成更复杂的验证,比如某些数据需要在服务端验证时。示例展示的是密码的二次确认及模拟的一个异步验证。

  1. <template>
  2. <Form ref="formCustom" :model="formCustom" :rules="ruleCustom" :label-width="80">
  3. <FormItem label="Password" prop="passwd">
  4. <Input type="password" v-model="formCustom.passwd"></Input>
  5. </FormItem>
  6. <FormItem label="Confirm" prop="passwdCheck">
  7. <Input type="password" v-model="formCustom.passwdCheck"></Input>
  8. </FormItem>
  9. <FormItem label="Age" prop="age">
  10. <Input type="text" v-model="formCustom.age" number></Input>
  11. </FormItem>
  12. <FormItem>
  13. <Button type="primary" @click="handleSubmit('formCustom')">Submit</Button>
  14. <Button @click="handleReset('formCustom')" style="margin-left: 8px">Reset</Button>
  15. </FormItem>
  16. </Form>
  17. </template>
  18. <script>
  19. export default {
  20. data () {
  21. const validatePass = (rule, value, callback) => {
  22. if (value === '') {
  23. callback(new Error('Please enter your password'));
  24. } else {
  25. if (this.formCustom.passwdCheck !== '') {
  26. // 对第二个密码框单独验证
  27. this.$refs.formCustom.validateField('passwdCheck');
  28. }
  29. callback();
  30. }
  31. };
  32. const validatePassCheck = (rule, value, callback) => {
  33. if (value === '') {
  34. callback(new Error('Please enter your password again'));
  35. } else if (value !== this.formCustom.passwd) {
  36. callback(new Error('The two input passwords do not match!'));
  37. } else {
  38. callback();
  39. }
  40. };
  41. const validateAge = (rule, value, callback) => {
  42. if (!value) {
  43. return callback(new Error('Age cannot be empty'));
  44. }
  45. // 模拟异步验证效果
  46. setTimeout(() => {
  47. if (!Number.isInteger(value)) {
  48. callback(new Error('Please enter a numeric value'));
  49. } else {
  50. if (value < 18) {
  51. callback(new Error('Must be over 18 years of age'));
  52. } else {
  53. callback();
  54. }
  55. }
  56. }, 1000);
  57. };
  58. return {
  59. formCustom: {
  60. passwd: '',
  61. passwdCheck: '',
  62. age: ''
  63. },
  64. ruleCustom: {
  65. passwd: [
  66. { validator: validatePass, trigger: 'blur' }
  67. ],
  68. passwdCheck: [
  69. { validator: validatePassCheck, trigger: 'blur' }
  70. ],
  71. age: [
  72. { validator: validateAge, trigger: 'blur' }
  73. ]
  74. }
  75. }
  76. },
  77. methods: {
  78. handleSubmit (name) {
  79. this.$refs[name].validate((valid) => {
  80. if (valid) {
  81. this.$Message.success('Success!');
  82. } else {
  83. this.$Message.error('Fail!');
  84. }
  85. })
  86. },
  87. handleReset (name) {
  88. this.$refs[name].resetFields();
  89. }
  90. }
  91. }
  92. </script>

Form 表单 - 图6

动态增减表单项

当需要动态维护 FormItem 时,也可以直接给 FormItem 设置属性 rules 来单独为该域做验证。

动态设置 FormItem 的 prop 属性时,会依据上层的 Form 组件的 model 来获取,查看示例代码。

FormItem 还可以独立设置 required、error 等属性,详见 API。

  1. <template>
  2. <Form ref="formDynamic" :model="formDynamic" :label-width="80" style="width: 300px">
  3. <FormItem
  4. v-for="(item, index) in formDynamic.items"
  5. v-if="item.status"
  6. :key="index"
  7. :label="'Item ' + item.index"
  8. :prop="'items.' + index + '.value'"
  9. :rules="{required: true, message: 'Item ' + item.index +' can not be empty', trigger: 'blur'}">
  10. <Row>
  11. <Col span="18">
  12. <Input type="text" v-model="item.value" placeholder="Enter something..."></Input>
  13. </Col>
  14. <Col span="4" offset="1">
  15. <Button @click="handleRemove(index)">Delete</Button>
  16. </Col>
  17. </Row>
  18. </FormItem>
  19. <FormItem>
  20. <Row>
  21. <Col span="12">
  22. <Button type="dashed" long @click="handleAdd" icon="md-add">Add item</Button>
  23. </Col>
  24. </Row>
  25. </FormItem>
  26. <FormItem>
  27. <Button type="primary" @click="handleSubmit('formDynamic')">Submit</Button>
  28. <Button @click="handleReset('formDynamic')" style="margin-left: 8px">Reset</Button>
  29. </FormItem>
  30. </Form>
  31. </template>
  32. <script>
  33. export default {
  34. data () {
  35. return {
  36. index: 1,
  37. formDynamic: {
  38. items: [
  39. {
  40. value: '',
  41. index: 1,
  42. status: 1
  43. }
  44. ]
  45. }
  46. }
  47. },
  48. methods: {
  49. handleSubmit (name) {
  50. this.$refs[name].validate((valid) => {
  51. if (valid) {
  52. this.$Message.success('Success!');
  53. } else {
  54. this.$Message.error('Fail!');
  55. }
  56. })
  57. },
  58. handleReset (name) {
  59. this.$refs[name].resetFields();
  60. },
  61. handleAdd () {
  62. this.index++;
  63. this.formDynamic.items.push({
  64. value: '',
  65. index: this.index,
  66. status: 1
  67. });
  68. },
  69. handleRemove (index) {
  70. this.formDynamic.items[index].status = 0;
  71. }
  72. }
  73. }
  74. </script>

API

Form props

属性说明类型默认值
model表单数据对象Object-
rules表单验证规则,具体配置查看 async-validatorObject-
inline是否开启行内表单模式Booleanfalse
label-position表单域标签的位置,可选值为 leftrighttopStringright
label-width表单域标签的宽度,所有的 FormItem 都会继承 Form 组件的 label-width 的值Number-
show-message是否显示校验错误信息Booleantrue
autocomplete原生的 autocomplete 属性,可选值为 off 或 onStringoff

Form methods

方法名说明参数
validate对整个表单进行校验,参数为检验完的回调,会返回一个 Boolean 表示成功与失败,支持 Promisecallback
validateField对部分表单字段进行校验的方法,参数1为需校验的 prop,参数2为检验完回调,返回错误信息callback
resetFields对整个表单进行重置,将所有字段值重置为空并移除校验结果

FormItem props

属性说明类型默认值
prop对应表单域 model 里的字段String-
label标签文本String-
label-width表单域标签的的宽度Number-
label-for指定原生的 label 标签的 for 属性,配合控件的 element-id 属性,可以点击 label 时聚焦控件。String-
required是否必填,如不设置,则会根据校验规则自动生成Boolean-
rules表单验证规则Object | Array-
error表单域验证错误信息, 设置该值会使表单验证状态变为error,并显示该错误信息String-
show-message是否显示校验错误信息Booleantrue

FormItem slot

名称说明
内容
labellabel 内容