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

自定义验证

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

<template>
    <Form ref="formCustom" :model="formCustom" :rules="ruleCustom" :label-width="80">
        <FormItem label="Password" prop="passwd">
            <Input type="password" v-model="formCustom.passwd"></Input>
        </FormItem>
        <FormItem label="Confirm" prop="passwdCheck">
            <Input type="password" v-model="formCustom.passwdCheck"></Input>
        </FormItem>
        <FormItem label="Age" prop="age">
            <Input type="text" v-model="formCustom.age" number></Input>
        </FormItem>
        <FormItem>
            <Button type="primary" @click="handleSubmit('formCustom')">Submit</Button>
            <Button @click="handleReset('formCustom')" style="margin-left: 8px">Reset</Button>
        </FormItem>
    </Form>
</template>
<script>
    export default {
        data () {
            const validatePass = (rule, value, callback) => {
                if (value === '') {
                    callback(new Error('Please enter your password'));
                } else {
                    if (this.formCustom.passwdCheck !== '') {
                        // 对第二个密码框单独验证
                        this.$refs.formCustom.validateField('passwdCheck');
                    }
                    callback();
                }
            };
            const validatePassCheck = (rule, value, callback) => {
                if (value === '') {
                    callback(new Error('Please enter your password again'));
                } else if (value !== this.formCustom.passwd) {
                    callback(new Error('The two input passwords do not match!'));
                } else {
                    callback();
                }
            };
            const validateAge = (rule, value, callback) => {
                if (!value) {
                    return callback(new Error('Age cannot be empty'));
                }
                // 模拟异步验证效果
                setTimeout(() => {
                    if (!Number.isInteger(value)) {
                        callback(new Error('Please enter a numeric value'));
                    } else {
                        if (value < 18) {
                            callback(new Error('Must be over 18 years of age'));
                        } else {
                            callback();
                        }
                    }
                }, 1000);
            };

            return {
                formCustom: {
                    passwd: '',
                    passwdCheck: '',
                    age: ''
                },
                ruleCustom: {
                    passwd: [
                        { validator: validatePass, trigger: 'blur' }
                    ],
                    passwdCheck: [
                        { validator: validatePassCheck, trigger: 'blur' }
                    ],
                    age: [
                        { validator: validateAge, trigger: 'blur' }
                    ]
                }
            }
        },
        methods: {
            handleSubmit (name) {
                this.$refs[name].validate((valid) => {
                    if (valid) {
                        this.$Message.success('Success!');
                    } else {
                        this.$Message.error('Fail!');
                    }
                })
            },
            handleReset (name) {
                this.$refs[name].resetFields();
            }
        }
    }
</script>

Form 表单 - 图6

动态增减表单项

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

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

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

<template>
    <Form ref="formDynamic" :model="formDynamic" :label-width="80" style="width: 300px">
        <FormItem
                v-for="(item, index) in formDynamic.items"
                v-if="item.status"
                :key="index"
                :label="'Item ' + item.index"
                :prop="'items.' + index + '.value'"
                :rules="{required: true, message: 'Item ' + item.index +' can not be empty', trigger: 'blur'}">
            <Row>
                <Col span="18">
                    <Input type="text" v-model="item.value" placeholder="Enter something..."></Input>
                </Col>
                <Col span="4" offset="1">
                    <Button @click="handleRemove(index)">Delete</Button>
                </Col>
            </Row>
        </FormItem>
        <FormItem>
            <Row>
                <Col span="12">
                    <Button type="dashed" long @click="handleAdd" icon="md-add">Add item</Button>
                </Col>
            </Row>
        </FormItem>
        <FormItem>
            <Button type="primary" @click="handleSubmit('formDynamic')">Submit</Button>
            <Button @click="handleReset('formDynamic')" style="margin-left: 8px">Reset</Button>
        </FormItem>
    </Form>
</template>
<script>
    export default {
        data () {
            return {
                index: 1,
                formDynamic: {
                    items: [
                        {
                            value: '',
                            index: 1,
                            status: 1
                        }
                    ]
                }
            }
        },
        methods: {
            handleSubmit (name) {
                this.$refs[name].validate((valid) => {
                    if (valid) {
                        this.$Message.success('Success!');
                    } else {
                        this.$Message.error('Fail!');
                    }
                })
            },
            handleReset (name) {
                this.$refs[name].resetFields();
            },
            handleAdd () {
                this.index++;
                this.formDynamic.items.push({
                    value: '',
                    index: this.index,
                    status: 1
                });
            },
            handleRemove (index) {
                this.formDynamic.items[index].status = 0;
            }
        }
    }
</script>

API

Form props

属性 说明 类型 默认值
model 表单数据对象 Object -
rules 表单验证规则,具体配置查看 async-validator Object -
inline 是否开启行内表单模式 Boolean false
label-position 表单域标签的位置,可选值为 leftrighttop String right
label-width 表单域标签的宽度,所有的 FormItem 都会继承 Form 组件的 label-width 的值 Number -
show-message 是否显示校验错误信息 Boolean true
autocomplete 原生的 autocomplete 属性,可选值为 off 或 on String off
hide-required-mark 4.0.0 是否隐藏所有表单项的必选标记 Boolean false
label-colon 4.0.0 是否自动在 label 名称后添加冒号 Boolean false
disabled 4.0.0 是否禁用该表单内的所有组件(适用于具有 disabled 属性的表单类组件) Boolean false

Form events

事件名 说明 返回值
on-validate 4.0.0 任一表单项被校验后触发,返回表单项 prop、校验状态、错误消息 prop, status, error

Form methods

方法名 说明 参数
validate 对整个表单进行校验,参数为检验完的回调,会返回一个 Boolean 表示成功与失败,支持 Promise callback
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 是否显示校验错误信息 Boolean true

FormItem slot

名称 说明
内容
label label 内容