1.7.0 新增
从 1.8.0 开始支持blur 时才触发校验以及 debounce,同 Validator 一样也开始支持异步校验。
表单,包含各种输入组件以及对应的校验;我们可以通过数据驱动的方式来生成完成表单。
默认配置使用
一个完整的包含所有的内置表单相关组件。
<cube-form
:model="model"
:schema="schema"
:immediate-validate="false"
:options="options"
@validate="validateHandler"
@submit="submitHandler"
@reset="resetHandler"></cube-form>
export default {
data() {
return {
validity: {},
valid: undefined,
model: {
checkboxValue: false,
checkboxGroupValue: [],
inputValue: '',
radioValue: '',
rateValue: 0,
selectValue: 2018,
switchValue: true,
textareaValue: '',
uploadValue: []
},
schema: {
groups: [
{
legend: '基础',
fields: [
{
type: 'checkbox',
modelKey: 'checkboxValue',
props: {
option: {
label: 'Checkbox',
value: true
}
},
rules: {
required: true
},
messages: {
required: 'Please check this field'
}
},
{
type: 'checkbox-group',
modelKey: 'checkboxGroupValue',
label: 'CheckboxGroup',
props: {
options: ['1', '2', '3']
},
rules: {
required: true
}
},
{
type: 'input',
modelKey: 'inputValue',
label: 'Input',
props: {
placeholder: '请输入'
},
rules: {
required: true
},
// validating when blur
trigger: 'blur'
},
{
type: 'radio-group',
modelKey: 'radioValue',
label: 'Radio',
props: {
options: ['1', '2', '3']
},
rules: {
required: true
}
},
{
type: 'select',
modelKey: 'selectValue',
label: 'Select',
props: {
options: [2015, 2016, 2017, 2018, 2019, 2020]
},
rules: {
required: true
}
},
{
type: 'switch',
modelKey: 'switchValue',
label: 'Switch',
rules: {
required: true
}
},
{
type: 'textarea',
modelKey: 'textareaValue',
label: 'Textarea',
rules: {
required: true
},
// debounce validate
// if set to true, the default debounce time will be 200(ms)
debounce: 100
}
]
},
{
legend: '高级',
fields: [
{
type: 'rate',
modelKey: 'rateValue',
label: 'Rate',
rules: {
required: true
}
},
{
type: 'upload',
modelKey: 'uploadValue',
label: 'Upload',
events: {
'file-removed': (...args) => {
console.log('file removed', args)
}
},
rules: {
required: true,
uploaded: (val, config) => {
return Promise.all(val.map((file, i) => {
return new Promise((resolve, reject) => {
if (file.uploadedUrl) {
return resolve()
}
// fake request
setTimeout(() => {
if (i % 2) {
reject(new Error())
} else {
file.uploadedUrl = 'uploaded/url'
resolve()
}
}, 1000)
})
})).then(() => {
return true
})
}
},
messages: {
uploaded: '上传失败'
}
}
]
},
{
fields: [
{
type: 'submit',
label: 'Submit'
},
{
type: 'reset',
label: 'Reset'
}
]
}
]
},
options: {
scrollToInvalidField: true,
layout: 'standard' // classic fresh
}
}
},
methods: {
submitHandler(e) {
e.preventDefault()
console.log('submit', e)
},
validateHandler(result) {
this.validity = result.validity
this.valid = result.valid
console.log('validity', result.validity, result.valid, result.dirty, result.firstInvalidFieldIndex)
},
resetHandler(e) {
console.log('reset', e)
}
}
}
model
就是整个表单需要的数据源,schema
就是生成表单所定义的模式,immediate-validate
如果为 true 则初始时立即做校验,options
则是配置选项。
submit
校验成功后提交事件,validate
每次有数据校验更新的事件,reset
则是重置事件。
自定义使用
你可以选择使用自己自定义的组件甚至通过插槽来自定义结构和行为。
<cube-form :model="model" @validate="validateHandler" @submit="submitHandler">
<cube-form-group>
<cube-form-item :field="fields[0]"></cube-form-item>
<cube-form-item :field="fields[1]"></cube-form-item>
<cube-form-item :field="fields[2]">
<cube-button @click="showDatePicker">{{model.dateValue || 'Please select date'}}</cube-button>
<date-picker ref="datePicker" :min="[2008, 8, 8]" :max="[2020, 10, 20]" @select="dateSelectHandler"></date-picker>
</cube-form-item>
</cube-form-group>
<cube-form-group>
<cube-button type="submit">Submit</cube-button>
</cube-form-group>
</cube-form>
// province, city, area
// select component
const PCA = {
props: {
value: {
type: Array,
default() {
return []
}
}
},
data() {
return {
selected: []
}
},
render(createElement) {
return createElement('cube-button', {
on: {
click: this.showPicker
}
}, this.selected.length ? this.selected.join(' ') : 'placeholder')
},
mounted() {
this.picker = this.$createCascadePicker({
title: 'PCA Select',
data: cityData,
selectedIndex: this.value,
onSelect: this.selectHandler
})
},
methods: {
showPicker() {
this.picker.show()
},
selectHandler(selectedVal, selectedIndex, selectedTxt) {
this.selected = selectedTxt
this.$emit('input', selectedVal)
}
}
}
export default {
data() {
return {
validity: {},
valid: undefined,
model: {
inputValue: '',
pcaValue: [],
dateValue: ''
},
fields: [
{
type: 'input',
modelKey: 'inputValue',
label: 'Input',
props: {
placeholder: '请输入'
},
rules: {
required: true
}
},
{
component: PCA,
modelKey: 'pcaValue',
label: 'PCASelect',
rules: {
required: true
},
messages: {
required: '请选择'
}
},
{
modelKey: 'dateValue',
label: 'Date',
rules: {
required: true
}
}
]
}
},
methods: {
submitHandler(e) {
console.log('submit')
},
validateHandler(result) {
this.validity = result.validity
this.valid = result.valid
console.log('validity', result.validity, result.valid, result.dirty, result.firstInvalidFieldIndex)
},
showDatePicker() {
this.$refs.datePicker.show()
},
dateSelectHandler(selectedVal) {
this.model.dateValue = new Date(selectedVal[0], selectedVal[1] - 1, selectedVal[2]).toDateString()
}
},
components: {
DatePicker
}
}
可以通过 component
指定实现了 v-model
的自定义组件,例如示例中的 PCA
组件;也可以通过使用插槽自定义结构行为,比如示例中的日期选择。
你可以利用 Form 组件的特性轻松实现类似问卷这种场景表单,组件示例源代码:https://github.com/didi/cube-ui/tree/dev/example/components/questionnaire
<demo-questionnaire
:tip="tip"
:questions="questions"
:submit="submit"
@submit="submitHandler"
/>
// source
// https://github.com/didi/cube-ui/tree/dev/example/components/questionnaire/questionnaire.vue
import DemoQuestionnaire from 'example/components/questionnaire/questionnaire.vue'
export default {
data() {
return {
tip: '请配合如实填写问卷,确保xxxx相关文案',
questions: [
{
type: 'switch',
model: 'switch',
title: '询问是否?'
// required: true
},
{
type: 'input',
model: 'input',
title: '输入',
options: {
placeholder: '请输入'
},
on: 'switch',
required: true
},
{
type: 'date',
model: 'date',
title: '日期',
options: {
// min: '2020-01-01',
// max: '2020-02-18'
},
required: true
},
{
type: 'time',
model: 'time',
title: '时间',
options: {
min: '01:00',
max: '23:59'
},
required: true
},
{
type: 'select',
model: 'select',
title: '选择',
options: [
'option1',
'option2',
'option3'
],
required: true
},
{
type: 'radio',
model: 'radio',
title: '单选',
options: [
'单选1',
'单选2',
'单选3'
],
required: true
},
{
type: 'checkbox',
model: 'checkbox',
title: '多选',
options: [
'多选1',
'多选2',
'多选3'
],
required: true
},
{
type: 'textarea',
model: 'textarea',
title: '多行文本',
on: {
model: 'checkbox',
options: ['多选1', '多选3']
},
required: true
},
{
type: 'checkbox',
row: true,
model: 'checkbox2',
title: '多选-横',
options: [
'多选-横1',
'多选-横2',
'多选-横3'
],
required: true
},
{
type: 'tel',
model: 'tel',
title: '手机号',
options: {
placeholder: '请输入手机号'
},
required: true
},
{
type: 'rate',
model: 'rate',
title: '级别',
options: {
max: 10
},
required: true
},
{
type: 'city',
model: 'city',
title: '城市',
required: true
},
{
type: 'upload',
model: 'upload',
title: '上传',
options: {
action: '//jsonplaceholder.typicode.com/photos/',
max: 2
},
required: true
},
{
type: 'agreement',
model: 'agreement',
options: {
text: '请同意',
link: {
text: '《xx协议》',
href: 'https://github.com/didi/cube-ui'
},
desc: '说明:本人承诺xx xxxxx xxx xx。'
},
required: true,
errMsg: '请同意协议'
}
],
submit: {
text: 'Submit'
}
}
},
components: {
DemoQuestionnaire
},
methods: {
submitHandler(model) {
console.log('submit', model)
}
}
}
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
model | 数据源 | Object | - | {} |
schema | 生成表单依赖的模式 | Object | - | {} |
immediateValidate | 初始化时是否立即校验 | Boolean | true/false | false |
action | 表单 Form action 的值 | String | - | undefined |
options | 配置项 | Object | - | { scrollToInvalidField: false, layout: 'standard' // or: classic |
submitAlwaysValidate1.12.36+ | 提交表单时是否总校验所有字段 | Boolean | true/false | false |
schema
子配置项
模式用于定义表单中的各个字段,可以选择是否分组。
无分组
直接包含 fields
即可:
{
fields: [
{
type: 'input',
modelKey: 'inputValue',
label: 'Input'
},
// ...
]
}
有分组
可以设置 groups
:
{
groups: [
{
legend: 'Group 1'
fields: [
{
type: 'input',
modelKey: 'inputValue',
label: 'Input'
},
// ...
]
},
{
legend: 'Group 2'
fields: [
{
type: 'input',
modelKey: 'inputValue',
label: 'Input'
},
// ...
]
}
]
}
不管有没有分组,我们都需要使用 fields
定义表单字段,其中每一项可以有如下属性:
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
type | 字段类型 | String | 默认内置的可选类型组件有:button , checkbox , checkbox-group , input , radio , radio-group , rate , select , switch , textarea , upload ;以及特殊的 submit 和 reset ,它们两个会被转换为对应类型的 button | - |
component | 字段使用的自定义组件,替换 type,该组件组件实现 v-model | Object/String | - | - |
modelKey | 在表单的 model 数据源对象中所对应的 key 名字 | String | - | - |
label | 字段的标签值 | String | - | - |
props | type 对应的组件或者自定义组件 component 所需要的 props | Object | - | - |
events1.8.0+ | type 对应的组件或者自定义组件 component 的事件回调 | Object | - | - |
rules | 字段的校验规则,参见 Validator | Object | - | - |
trigger1.8.0+ | 如果设置为 'blur' 那么则会在离焦后校验 | String | blur/change | - |
debounce1.8.0+ | 控制校验节奏,值为时间,单位 ms。如果 trigger 设置为 blur 则此项配置不生效 | Number/Boolean | >= 0,如果设置为 true,那么时间就是 200(ms) | - |
messages | 字段的校验消息,参见 Validator | String | - | - |
key1.12.36+ | 字段的唯一key,尤其适用在 schema 更新的场景中 | String | - | - |
options
子配置项
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
scrollToInvalidField | 是否默认滚动到第一个无效字段位置 | Boolean | true/false | false |
layout | 表单何种布局方式 | String | standard/classic/fresh | standard |
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
legend | 分组名字 | String | - | '' |
fields | 该组内所包含的字段集合 | Array | - | [] |
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
field | 字段数据 | Object | - | - |
事件名 | 说明 | 参数1 | 参数2 | 参数3 |
---|---|---|---|---|
submit | 表单校验通过后触发此事件,如果只有同步校验,则不会阻止默认行为,而如果包含了异步校验,则默认就会阻止默认行为 | e - 事件对象 | model 值 | 只包含存在的字段的 model 值1.12.30+ |
reset | 表单重置事件 | e - 事件对象 | - | - |
validate | 表单校验事件 | 参数结构如下: { validity, valid, invalid, dirty, firstInvalidFieldIndex } | - | - |
valid | 表单校验成功触发 | validity 校验结果 | - | - |
invalid | 表单校验失败触发 | validity 校验结果 | - | - |
validate
事件的参数
参数 | 说明 | 类型 |
---|---|---|
validity | 校验结果 | Object |
valid | 校验合法,如果还没校验则为 undefined,一旦校验则为 true 或 false | Boolean/Undefined |
invalid | 校验不合法,如果还没校验则为 undefined,一旦校验则为 true 或 false | Boolean |
dirty | 表单处于 dirty 状态,也就意味着数据源发生了变化 | Boolean |
firstInvalidFieldIndex | 第一个校验不合法的字段索引值 | Number |
校验结果 validity
对象
参数 | 说明 | 类型 |
---|---|---|
valid | 校验是否合法 | Boolean/Undefined |
result | 校验结果,类似于: { required: { valid: false, invalid: true, message: 'Required.' } } | Object |
dirty | 数据是否是已经更新过的 | Boolean |
方法名 | 说明 | 参数 | 返回值 |
---|---|---|---|
submit | 提交表单 | skipValidate, 默认 false,如果为 true 代表不校验 直接 submit1.12.2+ | - |
reset | 重置表单 | - | - |
validate(cb) | 校验表单 | cb: 校验完成后回调函数,主要用于异步校验场景,调用参数为 valid 的值 | 如果支持 Promise 的话返回值是 Promise 对象(只有 resolved 状态,值为 valid),否则 undefined |