Skip to content

表单 Form

用于收集信息。

基础使用

Form 用 model 传入表单数据对象,在 rules 中传入校验规则;FormItem 中 field 设置表单项字段,用于表单校验、重置等操作。

FormItem 的 rule 会覆盖 Form 的 rules 中相同 field 的规则定义。

当通过 Form 组件的 validate 方法手动触发表单校验时,组件将忽略 rulesrule 上配置的 trigger 条件,对所有存在的 FormItem 执行校验,并在遇到第一条不满足的规则时立即返回校验结果。

此外,需要注意的是,FormItem 的 field 不具有响应式。

Please select...
<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 的 modelform 属性必须传入其一。

<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 自定义表单校验条件。

The Answer to the Great Question Of Life, the Universe and Everything...

<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 的 disabledreadonly 属性会作用于其内部的所有按钮组件(包括 Button、ButtonGroup)以及各个 FormItem 内部的数据输入组件;而单个 FormItem 的 disabledreadonly 属性则仅影响该表单项内部的按钮组件和数据输入组件。

Form、FormItem 和其内部的按钮组和数据输入组件,这两个属性采用"或"逻辑,即任一被设为禁用或只读状态,其子树组件(或其自身)便会相应生效。

Disabled

Readonly

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

子元素宽度

通过 labelPropscontentProps 修改标签和内容区域的 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

ts
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

属性类型可选默认值描述版本
modelRecord<number | string, any>表单数据对象。formmodel 必须传入其一。0.0.3
formFormInstanceuseForm 返回的表单对象,用于以 hook 的形式操作表单。formmodel 必须传入其一。0.0.3
rulesRecord<string, RuleItem | RuleItem[]>验证规则。0.0.3
disabledbooleanfalse是否禁用。0.0.3
readonlybooleanfalse是否只读。0.0.3
size'small' | 'medium' | 'large''medium'表单尺寸。0.0.3
labelAlign'left' | 'right' | 'top''right'标签的对齐方式。0.0.3
showAsteriskboolean是否展示星号。0.0.3
asteriskPlacement'left' | 'right' | 'end''left'星号的位置。0.0.3
labelAutoWidthbooleanfalse表单项标签宽度自适应。0.0.3
rowPropsRowProps表单项行容器的属性。0.0.3
labelPropsColProps表单项标签列的属性。0.0.3
contentPropsColProps表单项内容列的属性。0.0.3

UseFormReturn

属性类型可选默认值描述版本
modelRef<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

事件参数描述版本
submitform: Record<number | string, any>, event: Event表单触发原生的提交时的回调。0.0.3
resetform: 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

属性类型可选默认值描述版本
requiredbooleanfalse是否为必填字段。0.0.3
messagestring验证失败时的提示信息,为空字符串时不会触发错误。0.0.3
triggerRuleTrigger | RuleTrigger[]['change', 'blur']触发验证的事件。0.0.3
typeFieldType | FieldType[]字段类型校验。0.0.3
maxnumber最大值限制,仅对数字值有效。0.0.3
minnumber最小值限制,仅对数字值有效。0.0.3
maxLengthnumber最大长度限制,仅当值为字符串或数组时有效。0.0.3
minLengthnumber最小长度限制,仅当值为字符串或数组时有效。0.0.3
emailbooleanfalse是否为邮箱地址,仅当值为字符串时有效。0.0.3
urlbooleanfalse是否为 URL,仅当值为字符串时有效。0.0.3
numberStringbooleanfalse是否为数字字符串,仅当值为字符串时有效。0.0.3
levelRuleLevel'error'验证失败的级别,只有 'error' 等级才会使表单校验失败。0.0.3
validator(value: any, model: Record<number | string, any>) => string | void | Promise<void | string>自定义验证函数,返回错误提示字符串,返回空值则为校验成功。0.0.3

FormItemProps

属性类型可选默认值描述版本
fieldstring关联的表单字段名,支持字段路径的形式,例如 'user[0].info.name'。该属性不具有响应式。0.0.3
labelstring标签文本。0.0.3
ruleRuleItem | RuleItem[]验证规则。0.0.3
disabledboolean是否禁用,和 Form 中的 disabled 取或运算决定最终是否禁用。0.0.3
readonlyboolean是否只读,和 Form 中的 readonly 取或运算决定最终是否只读。0.0.3
labelAlign'left' | 'right' | 'top'标签的对齐方式。0.0.3
showAsteriskboolean是否展示星号。0.0.3
asteriskPlacement'left' | 'right' | 'end'星号的位置。0.0.3
rowPropsRowProps表单项行容器的属性。0.0.3
labelPropsColProps表单项标签列的属性。0.0.3
contentPropsColProps表单项内容列的属性。0.0.3

FormItemSlots

插槽参数描述版本
tipmessage: string, level: RuleLevel验证提示。0.0.3
extra额外内容插槽,位于内容区域下方。0.0.3
label自定义标签。0.0.3
default表单项内容插槽。0.0.3

RuleLevel, FieldType, RuleTrigger, FormValidateResult

ts
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
		}>
	>
}>