Form/FormFooter/FormItem 表单
寄语:表单这块一直没有能深度去思考,之前做过一般跟其他 UI 库一样校验,但是都觉得不满意,现只保留最简单最布局功能。
注:
- 这几个组件主要聚焦于布局。
- 如果想要复杂的表单设计或者校验功能,可以借助 formilyjs 来实现。
vue
<template>
<ta-group title="基础">
<ta-form>
<ta-form-item label="昵称">
<ta-input v-model="baseForm.nickname" placeholder="请输入昵称" />
</ta-form-item>
<ta-form-item label="性别">
<ta-radio-group v-model="baseForm.gender" :options="genderOptions"></ta-radio-group>
</ta-form-item>
<template #footer>
<ta-button type="primary" @click="onBaseSubmit">提交</ta-button>
</template>
</ta-form>
</ta-group>
<ta-group title="Formily">
<FormProvider :form="form">
<Field
name="nickname"
title="昵称"
required
:component="[TaInput, { placeholder: '请输入昵称', showClear: true }]"
:decorator="[FormItem]"
/>
<Field
name="avatar"
title="头像"
required
:component="[TaImageUploader, { uploadReady: hookUpload, columnNumber: 1, maxCount: 1 }]"
:decorator="[FormItem]"
/>
<Field
name="gender"
title="性别"
required
:component="[
TaRadioGroup,
{
options: genderOptions
}
]"
:decorator="[FormItem]"
/>
<Field
name="weight"
title="体重Kg"
required
:component="[TaSlider, { showValue: true, min: 35, max: 120 }]"
:decorator="[FormItem]"
/>
<Field
name="season"
title="季节"
required
:component="[TaPicker, { options: multiOptions, placeholder: '选择季节' }]"
:decorator="[FormItem]"
/>
<Field
name="birthday"
title="生日"
required
:component="[TaCalendar, { placeholder: '选择生日' }]"
:decorator="[FormItem]"
/>
<Field
name="character"
title="性格"
required
:component="[TaCheckboxGroup, { options: characters }]"
:decorator="[FormItem]"
/>
<Field
name="region"
title="地区"
required
:component="[
TaCascader,
{
placeholder: '选择地区',
fieldNames: { value: 'label' },
options: regionOptions
}
]"
:decorator="[FormItem]"
/>
<Field
name="happinessIndex"
title="幸福指数"
required
:component="[TaRate, { allowHalf: true }]"
:decorator="[FormItem]"
/>
<Field
name="TaStepper"
title="步进器"
required
:component="[TaStepper, { max: 10, step: 0.2, decimalLength: 1 }]"
:decorator="[FormItem]"
/>
<Field name="agree" title="认可" required :component="[TaSwitch]" :decorator="[FormItem]" />
<FormConsumer>
<template #default="{ form }">
<pre class="exp-form-json">{{ JSON.stringify(form.values, null, 2) }}</pre>
<ta-form-footer>
<ta-button
type="primary"
@click="
() => {
form.submit(onSubmit)
}
"
>提交</ta-button
>
</ta-form-footer>
</template>
</FormConsumer>
</FormProvider>
</ta-group>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { multiOptions, regionOptions } from '../Picker/data'
import {
TaInput,
TaPicker,
TaCalendar,
TaCascader,
TaSwitch,
TaRate,
TaSlider,
TaRange,
TaStepper,
TaRadioGroup,
TaCheckboxGroup,
TaImageUploader,
showToast,
showDialog,
type ImageUploaderUploadReady
} from '@/index'
import { createForm, setValidateLanguage } from '@formily/core'
import { FormProvider, Field, FormConsumer } from '@formily/vue'
import FormItem from './FormItem'
setValidateLanguage('zh-CN')
export default defineComponent({
name: 'ExpForm',
components: { FormProvider, Field, FormConsumer },
setup() {
function getDataUrl(file: File) {
return new Promise<string>(resolve => {
const fr = new FileReader()
fr.onload = function (e) {
resolve((e.target?.result as string) ?? '')
}
fr.readAsDataURL(file)
})
}
const hookUpload: ImageUploaderUploadReady = (file, handlers) => {
getDataUrl(file).then(url => {
handlers.success(url)
})
}
return {
hookUpload
}
},
data() {
return {
baseForm: {
nickname: '',
gender: ''
},
FormItem,
TaInput,
TaPicker,
TaCalendar,
TaCascader,
TaSwitch,
TaRate,
TaSlider,
TaRange,
TaStepper,
TaRadioGroup,
TaCheckboxGroup,
TaImageUploader,
form: createForm({ validateFirst: true }),
genderOptions: [
{ label: '男', value: 1 },
{ label: '女', value: 2 }
],
regionOptions,
multiOptions,
characters: ['活泼', '内向', '高冷']
}
},
methods: {
onBaseSubmit() {
showDialog({
showCancel: false,
content: `nickname: ${this.baseForm.nickname}
gender: ${this.baseForm.gender}
`
})
},
onSubmit(...args: any[]) {
console.log(...args)
showToast('校验通过')
}
}
})
</script>
Import
js
import { TaForm, TaFormFooter, TaFormItem } from 'tantalum-ui-mobile'
具体的引入方式可以参考引入组件。
Form Slots
#default
vue
<ta-form>
<ta-input type="text" />
</ta-form>
footer
vue
<ta-form>
<template #footer>
<ta-button form-type="submit">提交</ta-button>
</template>
</ta-form>
FormFooter Slots
#default
vue
<ta-form-footer>
<ta-button form-type="submit">提交</ta-button>
</ta-form-footer>
FormItem Props
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
error | string | string[] | 否 | 错误提示信息 | |
label | string | 否 | 设置该行名称,比如 昵称 | |
required | boolean | false | 否 | 是否必填,设置 true 后 label 会展示必填* |
FormItem Slots
default
vue
<ta-form-item>
<ta-input type="text" />
</ta-form-item>
支持表单的组件
- Input
- RadioGroup
- CheckboxGroup
- Switch
- Stepper
- Slider
- Range
- Rate
- Calendar
- DatePicker
- Cascader
- Picker
- ImageUploader
与 Formily 配合
关于 Formily 的介绍可以查看阿里巴巴的官网。
安装
sh
npm install --save @formily/core @formily/vue
对 FormItem
做下适配
FormilyFormItem.js
:
js
import { TaFormItem } from 'tantalum-ui-mobile'
import { connect, mapProps } from '@formily/vue'
import { isVoidField } from '@formily/core'
export default connect(
TaFormItem,
mapProps({ validateStatus: true, title: 'label', required: true }, (props, field) => {
if (isVoidField(field)) return props
if (!field) return props
const getMessage = () => {
if (field.validating) return
if (props.error) return props.error
if (field.selfErrors.length) return field.selfErrors
// if (field.selfWarnings.length) return split(field.selfWarnings)
// if (field.selfSuccesses.length) return split(field.selfSuccesses)
}
return {
error: getMessage()
}
})
)
设计表单
vue
<template>
<FormProvider :form="form">
<Field
name="nickname"
title="昵称"
required
:component="[Input, { placeholder: '请输入昵称' }]"
:decorator="[FormilyFormItem]"
/>
<Field
name="gender"
title="性别"
required
:component="[
RadioGroup,
{
options: genderOptions
}
]"
:decorator="[FormilyFormItem]"
/>
<FormConsumer>
<template #default="{ form }">
<pre class="exp-form-json">{{ JSON.stringify(form.values, null, 2) }}</pre>
<ta-form-footer>
<ta-button
type="primary"
@click="
() => {
form.submit(onSubmit)
}
"
>提交</ta-button
>
</ta-form-footer>
</template>
</FormConsumer>
</FormProvider>
</template>
<script>
import { multiOptions, regionOptions } from '../Picker/data'
import { Input, RadioGroup, Dialog } from 'tantalum-ui-mobile'
import { createForm, setValidateLanguage } from '@formily/core'
import { FormProvider, Field, FormConsumer } from '@formily/vue'
import FormilyFormItem from './FormilyFormItem'
setValidateLanguage('zh-CN')
export default {
name: 'ExpForm',
components: { FormProvider, Field, FormConsumer },
data() {
return {
FormilyFormItem,
Input,
RadioGroup,
form: createForm({ validateFirst: true }),
genderOptions: [
{ label: '男', value: 1 },
{ label: '女', value: 2 }
]
}
},
methods: {
onBaseSubmit() {
Dialog.showDialog({
showCancel: false,
content: `nickname: ${this.baseForm.nickname}
gender: ${this.baseForm.gender}
`
})
}
}
}
</script>