• Form 表单
    • 概述
    • 代码示例
    • API
      • Form props
      • Form events
      • Form methods
      • FormItem props
      • FormItem slot

    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。

    <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-validatorObject-
    inline是否开启行内表单模式Booleanfalse
    label-position表单域标签的位置,可选值为 leftrighttopStringright
    label-width表单域标签的宽度,所有的 FormItem 都会继承 Form 组件的 label-width 的值Number-
    show-message是否显示校验错误信息Booleantrue
    autocomplete原生的 autocomplete 属性,可选值为 off 或 onStringoff
    hide-required-mark 4.0.0是否隐藏所有表单项的必选标记Booleanfalse
    label-colon 4.0.0是否自动在 label 名称后添加冒号Booleanfalse
    disabled 4.0.0是否禁用该表单内的所有组件(适用于具有 disabled 属性的表单类组件)Booleanfalse

    Form events

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

    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 内容