Form 表单
示例
基础样式
使用 actions
插槽来提供表单操作按钮。
<template>
<article>
<veui-form :data="formData">
<veui-field label="状态:">
<veui-select
v-model="formData.statusSelected"
:options="statusOptions"
/>
</veui-field>
<veui-field label="时间:">
<veui-datepicker
v-model="formData.range"
range
/>
</veui-field>
<veui-field>
<veui-search-box
v-model="formData.query"
placeholder="请输入搜索内容"
/>
</veui-field>
<template #actions>
<veui-button
ui="primary"
type="submit"
>
提交
</veui-button>
<veui-button>取消</veui-button>
</template>
</veui-form>
</article>
</template>
<script>
import { Form, Field, Button, Select, DatePicker, SearchBox } from 'veui'
export default {
components: {
'veui-form': Form,
'veui-field': Field,
'veui-button': Button,
'veui-select': Select,
'veui-datepicker': DatePicker,
'veui-search-box': SearchBox
},
data () {
const start = new Date()
const end = new Date(start.getFullYear(), start.getMonth() + 1, 0)
return {
statusOptions: [
{
label: '状态1',
value: 1
},
{
label: '状态2',
value: 2
},
{
label: '状态3',
value: 3
},
{
label: '状态4',
value: 4
}
],
formData: {
statusSelected: 1,
query: '',
range: [start, end]
}
}
}
}
</script>
只读状态
设置 readonly
来使内部表单项处于只读状态。
<template>
<article>
<section>
<veui-checkbox v-model="readonly">
只读
</veui-checkbox>
</section>
<veui-form
:data="formData"
:readonly="readonly"
>
<veui-field label="姓名:">
<veui-input v-model="formData.name"/>
</veui-field>
</veui-form>
</article>
</template>
<script>
import { Form, Field, Input, Checkbox } from 'veui'
export default {
components: {
'veui-checkbox': Checkbox,
'veui-form': Form,
'veui-field': Field,
'veui-input': Input
},
data () {
return {
readonly: true,
formData: {
name: ''
}
}
}
}
</script>
<style lang="less" scoped>
section {
margin-bottom: 20px;
}
</style>
禁用状态
设置 disabled
来使内部表单项处于禁用状态。
<template>
<article>
<section>
<veui-checkbox v-model="disabled">
禁用
</veui-checkbox>
</section>
<veui-form
:data="formData"
:disabled="disabled"
>
<veui-field label="姓名:">
<veui-input v-model="formData.name"/>
</veui-field>
</veui-form>
</article>
</template>
<script>
import { Form, Field, Input, Checkbox } from 'veui'
export default {
components: {
'veui-checkbox': Checkbox,
'veui-form': Form,
'veui-field': Field,
'veui-input': Input
},
data () {
return {
disabled: true,
formData: {
name: ''
}
}
}
}
</script>
<style lang="less" scoped>
section {
margin-bottom: 20px;
}
</style>
校验
<template>
<article>
<veui-form
ref="form"
:before-validate="beforeValidate"
:after-validate="afterValidate"
:readonly="isValidating"
:data="formData"
:validators="validators"
@invalid="handleInvalid"
>
<veui-field
name="name"
label="姓名"
rules="required"
>
<veui-input v-model="formData.name"/>
</veui-field>
<veui-field
name="age"
:rules="ageRule"
label="年龄"
>
<veui-input v-model="formData.age"/>
</veui-field>
<veui-field
name="desc"
rules="required"
label="介绍"
>
<veui-textarea
v-model="formData.desc"
rows="3"
/>
</veui-field>
<veui-fieldset
name="phoneSet"
label="电话"
required
>
<veui-field
name="phoneType"
:rules="numRequiredRule"
>
<veui-select
v-model="formData.phoneType"
:options="phoneTypeOptions"
/>
</veui-field>
<veui-field
name="phone"
:rules="numRequiredRule"
>
<veui-input v-model="formData.phone"/>
</veui-field>
</veui-fieldset>
<veui-field
name="hobby"
:rules="hobbyRule"
label="爱好"
tip="选择则至少选三个"
>
<veui-checkbox-group
v-model="formData.hobby"
:items="hobbyItems"
/>
</veui-field>
<veui-fieldset
label="预期收入"
class="salary"
tip="联合校验,下限必须小于上限"
required
>
<veui-field
name="start"
:rules="numRequiredRule"
>
<veui-input v-model="formData.start"/>
</veui-field>
<veui-span>-</veui-span>
<veui-field
name="end"
:rules="numRequiredRule"
>
<veui-input v-model="formData.end"/>
</veui-field>
<veui-span>万</veui-span>
</veui-fieldset>
<veui-field
label="收入下限"
name="floor"
:rules="[
{name: 'required', value: true},
{name: 'min', value: 3500, message: '最低收入不小于 3500'}
]"
>
<veui-number-input v-model="formData.floor"/>
</veui-field>
<veui-field
name="term"
:rules="termRequiredRule"
label="协议"
>
<veui-checkbox
v-model="formData.term"
>
我已阅读并同意工作协议
</veui-checkbox>
</veui-field>
<template #actions>
<veui-button
ui="primary"
:loading="isValidating"
type="submit"
>
提交
</veui-button>
<veui-button
:loading="isValidating"
@click="resetForm"
>
重置
</veui-button>
</template>
</veui-form>
</article>
</template>
<script>
import {
Form,
Fieldset,
Field,
Span,
Input,
Button,
Select,
Textarea,
Checkbox,
CheckboxGroup,
NumberInput
} from 'veui'
export default {
components: {
'veui-span': Span,
'veui-input': Input,
'veui-number-input': NumberInput,
'veui-button': Button,
'veui-form': Form,
'veui-fieldset': Fieldset,
'veui-field': Field,
'veui-select': Select,
'veui-checkbox': Checkbox,
'veui-checkbox-group': CheckboxGroup,
'veui-textarea': Textarea
},
data () {
return {
formData: {
name: 'liyunteng1',
name1: 'liyunteng2',
age: null,
desc: '',
hobby: ['🏸'],
phone: '18888888888',
phoneType: 'mobile',
start: null,
end: null,
term: null,
floor: 3501
},
hobbyItems: [
{
value: '⚽️',
label: '足球'
},
{
value: '🏀',
label: '篮球'
},
{
value: '🏸',
label: '羽毛球'
},
{
value: '🎾',
label: '网球'
}
],
phoneTypeOptions: [
{
label: '座机',
value: 'phone'
},
{
label: '手机',
value: 'mobile'
}
],
requiredRule: [
{
name: 'required',
value: true,
triggers: 'blur,input'
}
],
numRequiredRule: [
{
name: 'numeric',
value: true,
triggers: 'blur,input'
},
{
name: 'required',
value: true,
triggers: 'blur,input'
}
],
termRequiredRule: [
{
name: 'required',
value: true,
message: '请勾选阅读协议',
triggers: 'change'
}
],
dynamicNameRule: [
{
name: 'required',
value: true,
triggers: 'blur,input'
},
{
name: 'minLength',
value: 2
}
],
ageRule: [
{
name: 'required',
value: true,
triggers: 'input'
},
{
name: 'numeric',
value: true,
triggers: 'input'
},
{
name: 'maxLength',
value: 3,
triggers: 'change'
}
],
hobbyRule: [
{
name: 'minLength',
value: 3,
message: '至少选择三个爱好',
triggers: 'change'
}
],
isValidating: false,
validators: [
{
fields: ['start', 'end'],
handler (start, end) {
if (start == null || end == null) {
return true
}
if (parseInt(start, 10) >= parseInt(end, 10)) {
return {
start: '下限必须小于上限'
}
}
return true
},
triggers: ['change', 'submit,input']
},
{
fields: ['phone'],
validate (phone) {
return new Promise(function (resolve) {
setTimeout(function () {
let res
if (phone === '18888888888') {
res = {
phone: '该手机已被注册'
}
}
return resolve(res)
}, 3000)
})
},
triggers: ['input']
}
]
}
},
methods: {
beforeValidate () {
this.isValidating = true
},
afterValidate () {
this.isValidating = false
},
handleInvalid () {
this.isValidating = false
},
resetForm () {
this.$refs.form.reset()
}
}
}
</script>
API
属性
名称 | 类型 | 默认值 | 描述 | |||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
readonly | boolean= | false | 内部输入组件是否为只读状态。 | |||||||||||||||||||||||||||
disabled | boolean= | false | 内部输入组件是否为禁用状态。 | |||||||||||||||||||||||||||
data | Object | - | 表单绑定的数据,和表单中的输入组件通过 | |||||||||||||||||||||||||||
validators | Array<Object>= | - | 表单联合校验、异步校验器。项目类型为
| |||||||||||||||||||||||||||
before-validate | function= | - | 表单进入提交流程后,进行校验之前的 hook,传入参数为 (data) ,data 为表单 data 属性值的副本。支持返回 Promise ,返回值或 Promise.resolve 的值为 true 或 undefined 表示流程继续,其它返回值表示中断流程并触发 invalid 事件。 | |||||||||||||||||||||||||||
after-validate | function= | - | 表单校验成功后,触发 submit 事件之前的 hook,传入参数为 (data) ,与 beforeValidate 的入参是同一个引用。支持返回 Promise ,返回值或 Promise.resolve 的值为 true 或 undefined 表示流程继续,其它返回值表示中断流程并触发 invalid 事件。 |
插槽
名称 | 描述 |
---|---|
default | 可直接内联 Fieldset 或 Field 组件。无默认内容。 |
actions | 表单操作内容,如“提交”、“取消”按钮等。无默认内容。 |
事件
名称 | 描述 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
submit | 在原生
| |||||||||
invalid |
|
表单提交流程
表单校验逻辑
表单校验内部分为 Field
的 rule
校验和 validators
的校验。
Field
的rule
是单值、同步校验。详见表单项。validators
可以是多值、异步的校验。
validators: [
{
fields: ['start', 'end'],
validate (start, end) {
if (start == null || end == null) {
return true
}
if (parseInt(start, 10) >= parseInt(end, 10)) {
return {
start: '下限必须小于上限'
}
}
return true
},
triggers: ['change', 'submit,input']
},
{
fields: ['phone'],
validate (phone) {
return new Promise(function (resolve) {
setTimeout(function () {
let res
if (phone === '18888888888') {
res = {
phone: '该手机已被注册'
}
}
return resolve(res)
}, 3000)
})
},
triggers: ['input']
}
]
Field
的 rule
和 validators
的优先级
校验失败的信息会添加到对应的 Field
的 validities
信息中。由于同个操作触发的校验,validators
的校验结果优先级大于 Field
的 rule
,不同操作触发的校验,展现最后一个结果。Field
的 rule
内部的优先级,请参考其 rules
属性。
交互过程的校验
提交过程的校验
提交时,其中一个过程的校验失败不会导致整个校验终止,校验信息将在两个过程执行完毕后进行整合,并传递到 invalid
事件中去。