表单 Form
用于收集信息。
基础使用
Form 用 model 传入表单数据对象,在 rules 中传入校验规则;FormItem 中 field 设置表单项字段,用于表单校验、重置等操作。
FormItem 的
rule会覆盖 Form 的rules中相同field的规则定义。
当通过 Form 组件的
validate方法手动触发表单校验时,组件将忽略rules或rule上配置的trigger条件,对所有存在的 FormItem 执行校验,并在遇到第一条不满足的规则时立即返回校验结果。
此外,需要注意的是,FormItem 的
field不具有响应式。
<template>
<px-form
:model="form"
:rules="rules"
style="width: 500px"
@submit="submitHandler"
ref="formRef"
>
<px-form-item label="Input" field="input">
<px-input v-model="form.input" placeholder="Please input..."></px-input>
</px-form-item>
<px-form-item label="Radio" field="radio">
<px-radio-group
v-model="form.radio"
:options="radioOptions"
variant="retro"
></px-radio-group>
</px-form-item>
<px-form-item label="Checkbox" field="checkbox">
<px-checkbox-group v-model="form.checkbox" :options="checkboxOptions"></px-checkbox-group>
</px-form-item>
<px-form-item label="Number" field="number">
<px-input-number v-model="form.number" placeholder="Please input..."></px-input-number>
</px-form-item>
<px-form-item label="Tags" field="tags">
<px-input-tag v-model="form.tags" placeholder="Press enter to confirm..."></px-input-tag>
</px-form-item>
<px-form-item label="Text" field="text">
<px-textarea v-model="form.text" placeholder="Please input text..."></px-textarea>
</px-form-item>
<px-form-item label="Switch" field="switch">
<px-switch v-model="form.switch"></px-switch>
</px-form-item>
<px-form-item label="Select" field="select">
<px-select
:options="options"
v-model="form.select"
placeholder="Please select..."
></px-select>
</px-form-item>
<px-form-item label="Nest" field="nest.value">
<px-input v-model="form.nest.value" placeholder="Please input..."></px-input>
</px-form-item>
<px-form-item label="Email" field="email">
<px-input v-model="form.email" placeholder="Please email..."></px-input>
</px-form-item>
<px-form-item label="URL" field="url">
<px-input v-model="form.url" placeholder="Please URL..."></px-input>
</px-form-item>
<px-form-item label="Slider" field="slider">
<px-slider v-model="form.slider"></px-slider>
</px-form-item>
<px-form-item label="Number String" field="numberString">
<px-input v-model="form.numberString" placeholder="Please number..."></px-input>
</px-form-item>
<px-space justify="end">
<px-button native-type="submit">Submit</px-button>
<px-button theme="info" native-type="reset" style="margin-left: 8px">Reset</px-button>
</px-space>
</px-form>
</template>
<script setup lang="ts">
import { Form } from '@pixelium/web-vue'
// If on-demand import
// import { Form } from '@pixelium/web-vue/es'
import { ref, shallowRef } from 'vue'
const form = ref({
input: '',
number: 0,
tags: [] as string[],
text: '',
nest: {
value: ''
},
select: null as null | string,
email: '',
url: '',
numberString: '',
switch: false,
radio: null as null | string,
checkbox: [] as string[],
slider: 10
})
const rules = {
input: { required: true, message: 'Please input' },
select: { required: true, message: 'Please select' },
switch: { required: true, message: 'Please select' },
number: { min: 10, message: 'Min is 10' },
tags: [
{ required: true, message: 'Please input tags' },
{ maxLength: 5, message: 'Length less than or equal 5' }
],
text: { required: true, message: 'Just a tip', level: 'warning' },
'nest.value': { required: true, message: 'Please input' },
email: { required: true, email: true, message: 'Please input email' },
url: { required: true, url: true, message: 'Please input a URL' },
numberString: { required: true, numberString: true, message: 'Please input number' },
radio: {
required: true,
validator(value: string) {
return value !== 'Yes' ? 'Please select Yes' : undefined
}
},
checkbox: [
{ required: true, message: 'Please select' },
{ maxLength: 2, message: 'You can select up to 2 items' }
],
slider: { max: 90, message: 'Max is 90' }
}
const options = ref(['vue', 'react', 'angular'])
const radioOptions = ref(['Yes', 'No'])
const checkboxOptions = ref(['A', 'B', 'C', 'D'])
const formRef = shallowRef<null | InstanceType<typeof Form>>(null)
const submitHandler = () => {
formRef.value?.validate().then(({ isValid }) => {
if (isValid) {
console.log('submit')
}
})
}
</script>Hook 语法
useForm 会返回一个用于操作表单的对象,传入 Form 的 form 中即可。
Form 的
model和form属性必须传入其一。
<template>
<div style="width: 500px">
<px-form :form="userForm" :rules="userRules" label-auto-width>
<px-form-item field="username" label="Username">
<px-input v-model="userForm.model.value.username" placeholder="Username"></px-input>
</px-form-item>
<px-form-item field="email" label="Email">
<px-input v-model="userForm.model.value.email" placeholder="Email"></px-input>
</px-form-item>
<px-space justify="end">
<px-button @click="handleClearValidationUser" theme="info">Clear Validation</px-button>
<px-button @click="handleResetUser" theme="warning">Reset</px-button>
<px-button @click="handleSubmitUser">Submit</px-button>
</px-space>
</px-form>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@pixelium/web-vue'
// When on-demand import
// import { useForm } from '@pixelium/web-vue/es'
const userForm = useForm({
initialValues: { username: '', email: '' }
})
const userRules = {
username: [{ required: true, message: 'Please input username' }],
email: [{ required: true, email: true, message: 'Please input valid email' }]
}
const handleSubmitUser = () => {
userForm.validate().then(({ isValid }) => {
if (isValid) {
console.log('Submit User Form')
}
})
}
const handleResetUser = () => {
userForm.reset()
}
const handleClearValidationUser = () => {
userForm.clearValidation()
}
</script>自定义校验
使用 validator 自定义表单校验条件。
<template>
<px-form :model="form" :rules="rules" style="width: 600px" ref="formRef">
<p>The Answer to the Great Question Of Life, the Universe and Everything...</p>
<px-form-item label="Answer" field="number" label-align="left">
<px-input-number v-model="form.number"></px-input-number>
</px-form-item>
</px-form>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const form = ref({
number: 0
})
const rules = {
number: {
validator: (value: number | null) => {
if (value === 42) {
return
}
return 'Could you think again?'
}
}
}
</script>禁用 & 只读
通过 disabled 设置表单禁用状态,通过 readonly 设置表单只读状态。
表单组件 Form 的
disabled或readonly属性会作用于其内部的所有按钮组件(包括 Button、ButtonGroup)以及各个 FormItem 内部的数据输入组件;而单个 FormItem 的disabled或readonly属性则仅影响该表单项内部的按钮组件和数据输入组件。
Form、FormItem 和其内部的按钮组和数据输入组件,这两个属性采用"或"逻辑,即任一被设为禁用或只读状态,其子树组件(或其自身)便会相应生效。
<template>
<px-space>
<px-form
:model="form"
:rules="rules"
style="width: 500px"
@submit="submitHandler"
ref="formRef"
disabled
>
<h4>Disabled</h4>
<px-form-item label="Username" field="username">
<px-input v-model="form.username" placeholder="Please input username..."></px-input>
</px-form-item>
<px-form-item label="Email" field="email">
<px-input v-model="form.email" placeholder="Please email..."></px-input>
</px-form-item>
<px-space justify="end">
<px-button native-type="submit">Submit</px-button>
<px-button theme="info" native-type="reset" style="margin-left: 8px">Reset</px-button>
</px-space>
</px-form>
<px-form
:model="form"
:rules="rules"
style="width: 500px"
@submit="submitHandler"
ref="formRef"
readonly
>
<h4>Readonly</h4>
<px-form-item label="Username" field="username">
<px-input v-model="form.username" placeholder="Please input username..."></px-input>
</px-form-item>
<px-form-item label="Email" field="email">
<px-input v-model="form.email" placeholder="Please email..."></px-input>
</px-form-item>
<px-space justify="end">
<px-button native-type="submit">Submit</px-button>
<px-button theme="info" native-type="reset" style="margin-left: 8px">Reset</px-button>
</px-space>
</px-form>
</px-space>
</template>
<script setup lang="ts">
import { Form } from '@pixelium/web-vue'
// If on-demand import
// import { Form } from '@pixelium/web-vue/es'
import { ref, shallowRef } from 'vue'
const form = ref({
username: '',
email: ''
})
const rules = {
username: { required: true, message: 'Please input' },
email: { required: true, email: true, message: 'Please input email' }
}
const formRef = shallowRef<null | InstanceType<typeof Form>>(null)
const submitHandler = () => {
formRef.value?.validate().then(({ isValid }) => {
if (isValid) {
console.log('submit')
}
})
}
</script>标签对齐
通过 labelAlign 设置标签对齐方向
<template>
<px-space direction="vertical">
<px-form :model="form" label-align="top" style="width: 500px">
<px-form-item label="Input" field="input">
<px-input v-model="form.input"></px-input>
</px-form-item>
</px-form>
<px-form :model="form" style="width: 500px" label-align="left">
<px-form-item label="Input" field="input">
<px-input v-model="form.input"></px-input>
</px-form-item>
</px-form>
<px-form :model="form" style="width: 500px">
<px-form-item label="Input" field="input">
<px-input v-model="form.input"></px-input>
</px-form-item>
</px-form>
</px-space>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const form = ref({
input: ''
})
</script>子元素宽度
通过 labelProps 和 contentProps 修改标签和内容区域的 Col 组件属性。
设置 labelAutoWidth 标签区域宽度会进行自适应,内容区域宽度也会一同变化。
<template>
<px-space direction="vertical">
<px-form
:model="form"
style="width: 500px"
:label-props="{ span: 4 }"
:content-props="{ span: 20 }"
>
<px-form-item label="Input" field="input">
<px-input v-model="form.input"></px-input>
</px-form-item>
</px-form>
<px-form :model="form" style="width: 500px" label-auto-width>
<px-form-item label="Input" field="input">
<px-input v-model="form.input"></px-input>
</px-form-item>
</px-form>
</px-space>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const form = ref({
input: ''
})
</script>表单尺寸
表单有不同的大小。
表单组件 Form 的
size属性会作用于其内部的所有按钮组件(包括 Button、ButtonGroup)以及各个 FormItem 内部的数据输入组件。
Form、FormItem 内部的按钮组和数据输入组件,
size属性如果没有传入或为undefined,则设置为与 Form 的size属性相同,如果设置,则传入的值优先。
<template>
<px-space direction="vertical">
<px-radio-group v-model="formSize" :options="radioSizeOptions"></px-radio-group>
<px-form
label-auto-width
:model="form"
:size="formSize"
style="width: 500px"
@submit="submitHandler"
>
<px-form-item label="Input" field="input">
<px-input v-model="form.input"></px-input>
</px-form-item>
<px-form-item label="Number" field="number">
<px-input-number v-model="form.number"></px-input-number>
</px-form-item>
<px-form-item label="Radio" field="radio">
<px-radio-group
v-model="form.radio"
:options="radioOptions"
variant="retro"
></px-radio-group>
</px-form-item>
<px-form-item label="Checkbox" field="checkbox">
<px-checkbox-group
v-model="form.checkbox"
:options="checkboxOptions"
></px-checkbox-group>
</px-form-item>
<px-form-item label="Switch" field="switch">
<px-switch v-model="form.switch"></px-switch>
</px-form-item>
<px-space justify="end">
<px-button native-type="submit">Submit</px-button>
</px-space>
</px-form>
</px-space>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const form = ref({
input: 'text',
number: 114,
radio: 'Yes',
switch: false,
checkbox: [] as string[]
})
const submitHandler = () => {
console.log('submit')
}
const radioOptions = ref(['Yes', 'No'])
const radioSizeOptions = ref([
{ label: 'Small', value: 'small' },
{ label: 'Medium', value: 'medium' },
{ label: 'Large', value: 'large' }
])
const checkboxOptions = ref(['A', 'B', 'C', 'D'])
const formSize = ref('medium')
</script>API
useForm
function useForm<T extends Record<string | number, any> = Record<string | number, any>>(options?: {
initialValues?: T;
}): UseFormReturn<T>
export interface UseFormReturn<
T extends Record<string | number, any> = Record<string | number, any>
> {
model: Ref<T>
validate: (field?: string | string[]) => FormValidateResult
reset: (field?: string | string[]) => void
clearValidation: (field?: string | string[]) => void
register: (registerOptions: UseFormRegisterOptions) => void
}FormProps
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| model | Record<number | string, any> | 是 | | 表单数据对象。form 和 model 必须传入其一。 | 0.0.3 |
| form | FormInstance | 是 | | useForm 返回的表单对象,用于以 hook 的形式操作表单。form 和 model 必须传入其一。 | 0.0.3 |
| rules | Record<string, RuleItem | RuleItem[]> | 是 | | 验证规则。 | 0.0.3 |
| disabled | boolean | 是 | false | 是否禁用。 | 0.0.3 |
| readonly | boolean | 是 | false | 是否只读。 | 0.0.3 |
| size | 'small' | 'medium' | 'large' | 是 | 'medium' | 表单尺寸。 | 0.0.3 |
| labelAlign | 'left' | 'right' | 'top' | 是 | 'right' | 标签的对齐方式。 | 0.0.3 |
| showAsterisk | boolean | 是 | | 是否展示星号。 | 0.0.3 |
| asteriskPlacement | 'left' | 'right' | 'end' | 是 | 'left' | 星号的位置。 | 0.0.3 |
| labelAutoWidth | boolean | 是 | false | 表单项标签宽度自适应。 | 0.0.3 |
| rowProps | RowProps | 是 | | 表单项行容器的属性。 | 0.0.3 |
| labelProps | ColProps | 是 | | 表单项标签列的属性。 | 0.0.3 |
| contentProps | ColProps | 是 | | 表单项内容列的属性。 | 0.0.3 |
UseFormReturn
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| model | Ref<Record<string | number, any>> | 否 | | 表单数据对象。 | 0.0.3 |
| validate | (field?: string | string[]) => FormValidateResult | 否 | | 手动触发表单验证,无参数时验证所有字段,Form 挂载后方可调用。 | 0.0.3 |
| reset | (field?: string | string[]) => void | 否 | | 手动触发表单重置,无参数时验证所有字段,Form 挂载后方可调用。 | 0.0.3 |
| clearValidation | (field?: string | string[]) => void | 否 | | 清除表单验证状态,无参数时清除所有字段,Form 挂载后方可调用。 | 0.0.3 |
FormEvents
| 事件 | 参数 | 描述 | 版本 |
|---|---|---|---|
| submit | form: Record<number | string, any>, event: Event | 表单触发原生的提交时的回调。 | 0.0.3 |
| reset | form: Record<number | string, any>, event: Event | 表单触发原生的重置时触发的回调。 | 0.0.3 |
FormSlots
| 插槽 | 参数 | 描述 | 版本 |
|---|---|---|---|
| default | | 用于渲染表单项。 | 0.0.3 |
FormExpose
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| validate | (field?: string | string[]) => FormValidateResult | 否 | | 手动触发表单验证,无参数时验证所有字段。 | 0.0.3 |
| reset | (field?: string | string[]) => void | 否 | | 手动触发表单重置,无参数时重置所有字段。 | 0.0.3 |
| clearValidation | (field?: string | string[]) => void | 否 | | 清除表单验证状态,无参数时清除所有字段。 | 0.0.3 |
RuleItem
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| required | boolean | 是 | false | 是否为必填字段。 | 0.0.3 |
| message | string | 是 | | 验证失败时的提示信息,为空字符串时不会触发错误。 | 0.0.3 |
| trigger | RuleTrigger | RuleTrigger[] | 是 | ['change', 'blur'] | 触发验证的事件。 | 0.0.3 |
| type | FieldType | FieldType[] | 是 | | 字段类型校验。 | 0.0.3 |
| max | number | 是 | | 最大值限制,仅对数字值有效。 | 0.0.3 |
| min | number | 是 | | 最小值限制,仅对数字值有效。 | 0.0.3 |
| maxLength | number | 是 | | 最大长度限制,仅当值为字符串或数组时有效。 | 0.0.3 |
| minLength | number | 是 | | 最小长度限制,仅当值为字符串或数组时有效。 | 0.0.3 |
boolean | 是 | false | 是否为邮箱地址,仅当值为字符串时有效。 | 0.0.3 | |
| url | boolean | 是 | false | 是否为 URL,仅当值为字符串时有效。 | 0.0.3 |
| numberString | boolean | 是 | false | 是否为数字字符串,仅当值为字符串时有效。 | 0.0.3 |
| level | RuleLevel | 是 | 'error' | 验证失败的级别,只有 'error' 等级才会使表单校验失败。 | 0.0.3 |
| validator | (value: any, model: Record<number | string, any>) => string | void | Promise<void | string> | 是 | | 自定义验证函数,返回错误提示字符串,返回空值则为校验成功。 | 0.0.3 |
FormItemProps
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| field | string | 是 | | 关联的表单字段名,支持字段路径的形式,例如 'user[0].info.name'。该属性不具有响应式。 | 0.0.3 |
| label | string | 是 | | 标签文本。 | 0.0.3 |
| rule | RuleItem | RuleItem[] | 是 | | 验证规则。 | 0.0.3 |
| disabled | boolean | 是 | | 是否禁用,和 Form 中的 disabled 取或运算决定最终是否禁用。 | 0.0.3 |
| readonly | boolean | 是 | | 是否只读,和 Form 中的 readonly 取或运算决定最终是否只读。 | 0.0.3 |
| labelAlign | 'left' | 'right' | 'top' | 是 | | 标签的对齐方式。 | 0.0.3 |
| showAsterisk | boolean | 是 | | 是否展示星号。 | 0.0.3 |
| asteriskPlacement | 'left' | 'right' | 'end' | 是 | | 星号的位置。 | 0.0.3 |
| rowProps | RowProps | 是 | | 表单项行容器的属性。 | 0.0.3 |
| labelProps | ColProps | 是 | | 表单项标签列的属性。 | 0.0.3 |
| contentProps | ColProps | 是 | | 表单项内容列的属性。 | 0.0.3 |
FormItemSlots
| 插槽 | 参数 | 描述 | 版本 |
|---|---|---|---|
| tip | message: string, level: RuleLevel | 验证提示。 | 0.0.3 |
| extra | | 额外内容插槽,位于内容区域下方。 | 0.0.3 |
| label | | 自定义标签。 | 0.0.3 |
| default | | 表单项内容插槽。 | 0.0.3 |
RuleLevel, FieldType, RuleTrigger, FormValidateResult
export type RuleLevel = 'error' | 'warning' | 'success' | 'normal'
export type FieldType = 'number' | 'string' | 'boolean' | 'array' | 'dict' | 'function' | 'date'
export type RuleTrigger = 'blur' | 'change' | 'input'
export type FormValidateResult = Promise<{
isValid: boolean
results: Record<
string,
PromiseSettledResult<{
message: string
level: RuleLevel
}>
>
}>