Skip to content

Form表单

用于数据校验和提交

按钮导致的表单提交

3.0.11 之前

Form 组件下存在 button 时,点击 button 会默认触发表单验证

这并不是 bug,这是HTML的标准行为,button 的默认type就是 submit

不想触发该行为的话将 button 的 type 设置了 button 即可

该问题已于2.6.10解决,无需额外处理,已自动阻止表单自动提交事件

排列方向

通过修改 Formalign 属性可以实现,整体的水平或者垂直排列方式

考虑到一些情况下可能需要更为灵活的排列方式 故此 FormItem 也可以设置 align 属性来修改对齐方式,该项优先级更大

两者的 align 可选值有 horizontal vertical ,默认为 horizontal

Form设置align为vertical

Form设置align为horizontal

Form设置align为vertical,email项设置align为horizontal

vue
<template>
  <div class="space-y-2">
    <p class="font-bold">Form设置align为vertical</p>
    <Form :form="form" :schema="schema" align="vertical">
      <FormItem name="email" label="邮箱">
        <TextInput v-model="form.email" placeholder="请输入邮箱" />
      </FormItem>
      <FormItem name="password" label="密码">
        <TextInput v-model="form.password" type="password" placeholder="请输入密码" />
      </FormItem>
    </Form>

    <p class="font-bold">Form设置align为horizontal</p>
    <Form :form="form" :schema="schema" align="horizontal">
      <FormItem name="email" label="邮箱">
        <TextInput v-model="form.email" placeholder="请输入邮箱" />
      </FormItem>
      <FormItem name="password" label="密码">
        <TextInput v-model="form.password" type="password" placeholder="请输入密码" />
      </FormItem>
    </Form>

    <p class="font-bold">Form设置align为vertical,email项设置align为horizontal</p>
    <Form :form="form" :schema="schema" align="vertical">
      <FormItem name="email" label="邮箱" align="horizontal">
        <TextInput v-model="form.email" placeholder="请输入邮箱" />
      </FormItem>
      <FormItem name="password" label="密码">
        <TextInput v-model="form.password" type="password" placeholder="请输入密码" />
      </FormItem>
    </Form>
  </div>
</template>

<script setup lang="ts">
import { Form, FormItem, useYup, TextInput } from 'li-daisy'

import { ref } from 'vue'

const form = ref({
  email: '',
  password: '',
  status: true,
})

const yup = useYup()
const schema = yup.object({
  email: yup.string().email().required('请输入邮箱').trim(),
  password: yup.string().required('请输入密码').min(6).trim(),
  status: yup.bool().isTrue('状态错误'),
})
</script>

使用yup验证

Form 组件由 vee-validateyup 封装而成,yup 作为其认证库

组件内部封装了一个简单的 yup 全局实例,其代码见 仓库源码

借此,用户可以自行选择如何使用 yup,如果需要更小的打包体积建议使用按需从 yup 导入,即不要使用 import * as yup from 'yup' 这种方式去使用 yup

同理用户可以自行定义一系列基础配置,比如基础验证消息中文翻译,i18n

下面将演示如何去使用 yup ,以及如何实现一个简单的配置

vue
<template>
  <Form :form="form" label-width="40px" :schema="schema" align="vertical">
    <FormItem name="email" label="邮箱">
      <TextInput v-model="form.email" placeholder="请输入邮箱" />
    </FormItem>
    <FormItem name="password" label="密码">
      <TextInput v-model="form.password" type="password" placeholder="请输入密码" />
    </FormItem>
  </Form>
</template>

<script setup lang="ts">
import { Form, FormItem, TextInput } from 'li-daisy'
import * as yupInstance from 'yup'
import { ref } from 'vue'

const useYup = () => {
  yupInstance.setLocale({
    string: {
      email: '${path} 必须是有效的邮箱地址',
      min: '${path} 必须是长度不小于 ${min} 个字符',
    },
  })
  return yupInstance
}

const form = ref({
  email: '',
  password: '',
  status: true,
})

const yup = useYup()

const schema = yup.object({
  email: yup.string().email().required('请输入邮箱').trim(),
  password: yup.string().required('请输入密码').min(6).trim(),
})
</script>

例子

验证表单(注册示例)

通过 FormRefvalidate 方法校验整个表单,返回一个 Promise

校验通过时进入 then 回调,校验失败时进入 catch 回调

该方法只校验单个字段,失败时智慧展示所有字段的错误提示

vue
<template>
  <Form ref="formRef" :form="form" :schema="schema" align="vertical">
    <FormItem name="email" label="邮箱">
      <TextInput v-model="form.email" placeholder="请输入邮箱" />
    </FormItem>
    <FormItem name="password" label="密码">
      <TextInput v-model="form.password" type="password" placeholder="请输入密码" />
    </FormItem>
    <FormItem name="re_password" label="重复密码">
      <TextInput v-model="form.re_password" type="password" placeholder="请重复输入密码" />
    </FormItem>
    <FormItem>
      <button class="btn w-full" @click="handleRegister">注册用户</button>
    </FormItem>
  </Form>
</template>

<script setup lang="ts">
import { Form, FormItem, useYup, TextInput, Notification, Message } from 'li-daisy'

import type { FormRef } from 'li-daisy'
import { ref } from 'vue'

const formRef = ref<FormRef>()

const form = ref({
  email: '',
  password: '',
  re_password: '',
})

const yup = useYup()

const schema = yup.object({
  email: yup.string().email().required('请输入邮箱').trim(),
  password: yup
    .string()
    .required('请输入密码')
    .min(8, '密码不得少于八位')
    .matches(
      /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/,
      '密码必须包含大小写字母、数字和特殊字符'
    )
    .trim(),
  re_password: yup
    .string()
    .required('请再次输入密码')
    .oneOf([yup.ref('password')], '两次密码输入不一致'),
})

const handleRegister = async () => {
  formRef.value
    ?.validate()
    .then(() => {
      Message.info('注册成功')
    })
    .catch(() => {
      Notification.warning({
        title: '表单验证失败',
        message: '表单填写有误',
      })
    })
}
</script>

验证单个字段

通过 FormRefvalidateField 方法校验指定字段,返回一个 Promise

校验通过时进入 then 回调,校验失败时进入 catch 回调,并可获取错误信息

该方法只校验单个字段,失败时智慧展示指定字段的错误提示

vue
<template>
  <Form ref="formRef" :form="form" :schema="schema" align="vertical">
    <FormItem name="email" label="邮箱">
      <TextInput v-model="form.email" placeholder="请输入邮箱" />
    </FormItem>
    <FormItem name="password" label="密码">
      <TextInput v-model="form.password" type="password" placeholder="请输入密码" />
    </FormItem>
    <FormItem>
      <div class="space-y-3">
        <button class="btn w-full" @click="handleValidateEmail">验证邮箱</button>
        <button class="btn w-full" @click="handleValidatePassword">验证密码</button>
      </div>
    </FormItem>
  </Form>
</template>

<script setup lang="ts">
import { Form, FormItem, useYup, TextInput, Notification, Message } from 'li-daisy'
import type { FormRef } from 'li-daisy'

import { ref } from 'vue'

const formRef = ref<FormRef>()

const form = ref({
  email: '',
  password: '',
})

const yup = useYup()

const schema = yup.object({
  email: yup.string().email().required('请输入邮箱').trim(),
  password: yup.string().required('请输入密码').min(6).trim(),
})

const handleValidateEmail = () => {
  formRef.value
    ?.validateField('email')
    .then(() => {
      Message.info('注册成功')
    })
    .catch(err => {
      Notification.warning({
        title: '验证失败',
        message: err,
      })
    })
}

const handleValidatePassword = () => {
  formRef.value
    ?.validateField('password')
    .then(() => {
      Message.info('注册成功')
    })
    .catch(err => {
      Notification.warning({
        title: '验证失败',
        message: err,
      })
    })
}
</script>

检测验证是否通过

提供两种互补方式,选择取决于场景(UI 状态 vs 提交时需触发异步 schema 规则)。

  • isValid(响应式)

    • 描述:响应式布尔值,用于反映当前表单是否有错误(基于内部 errors)。
    • 适用场景:实时 UI 控制,例如禁用/启用提交按钮、显示简单状态提示。
    • 注意:不会主动触发 yup 的异步 test 或远程校验,仅反映已被触发并记录的错误状态。
  • validate / validateField(手动触发的异步校验)

    • 描述:调用时会执行 yup schema 上的所有规则(包括自定义的异步 test),返回 Promise。
    • validate(): 校验整个表单,常用于提交前的最终校验。
    • validateField(name): 校验单个字段,适合失焦校验或需要远程校验的场景。
    • 适用场景:提交时需等待异步规则(如远程唯一性校验)、对单字段做即时校验。

API

Attributes

Form

属性值说明类型默认值
form待验证的响应对象Ref<Record<string, any>>
Reactive<Record<string, any>>
-
schemayup验证规则GenericObject-
label-widthlabel宽度string'60px'
align对齐方向['horizontal','vertical']'vertical'

FormItem

属性值说明类型默认值
nameschema的keystring-
labellabel名string-
trigger错误信息显示时机['change','blur','input']'change'
align对齐方向['horizontal','vertical']'vertical'

Slots

Form

插槽名说明
default默认插槽

FormItem

插槽名说明
default默认插槽

Expose

Form

方法名说明类型
validate验证整个表单() => Promise<void>
validateField验证某个字段(fieldName: string) => Promise<void>
isValid验证是否通过boolean