vue-uform 一个灵活的,组件优先的表单验证库

801 阅读3分钟

简介

vue-uform 是一个面向组件、无内置样式的 Vue 3 表单处理与验证库。

设计目标为:

  • 组件优先:表单、字段、提交按钮都是 Vue 组件,使用模板即可声明式构建表单。
  • 无样式:不强制任何样式,完全交给用户或 UI 框架。
  • 灵活的布局:可以为单个字段自定义结构,也可以为整个表单统一应用布局(scheme)。
  • 内置与自定义验证:提供常用规则,并允许用户注册自定义规则(支持带参数)。
  • f-model:配套小型 Vite 插件提供 f-model 语法糖,减少 :value + @input 的重复编写。

安装

pnpm install vue-uform
pnpm install @vue-uform/vite-plugin -D

在 vite.config.ts 中添加插件:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uForm from '@vue-uform/vite-plugin'

export default defineConfig({
  plugins: [vue(), uForm()],
})

在 main.ts 中注册 Vue 插件:

import { createApp } from 'vue'
import App from './App.vue'
import { plugin as uformPlugin } from 'vue-uform'

createApp(App).use(uformPlugin, {}).mount('#app')

快速上手

最简示例:

<script setup>
const formValues = { username: '', password: '' }

function doLogin(data) {
  console.log('Form submit:', data)
}
</script>

<template>
  <u-form :values="formValues" @submit="doLogin">
    <u-field name="username" label="Username" validation="required" v-slot="{ value, update }">
      <input f-model />
    </u-field>

    <u-field name="password" label="Password" validation="required|min:6" v-slot="{ value, update }">
      <input type="password" f-model />
    </u-field>

    <u-submit>Login</u-submit>
  </u-form>
</template>

注:f-model 是通过 @vue-uform/vite-plugin 提供的语法糖,会被编译为等价的 :value 与事件监听。


内置验证规则

你可以在 的 validation 属性中直接使用这些规则,多个规则用 | 分隔,参数用 : 传入,多个参数用逗号 , 分隔。例如:validation="required|alpha|min:3|max:12"。

自定义验证规则(带参数)示例

下面是一个 min_words 的示例,检查输入文本至少包含指定数量的单词。此规则会接收来自 validation="min_words:5" 的参数 5。

<script setup lang="ts">
import { FieldNode } from "vue-uform"

// Custom rule: min_words
function minWords(node: FieldNode, min: number): boolean | string {
  const value = String(node.value.value || "").trim()
  if (!value) {
    return `Please enter at least ${min} words.`
  }
  const wordCount = value.split(/\s+/).length
  return wordCount >= min || `Please enter at least ${min} words.`
}
</script>
<template>
  <u-form>
    <u-field
      name="bio"
      label="Short Bio"
      validation="min_words:5"
      :rules="{ min_words: minWords }"
      v-slot="{ value, update }"
    >
      <textarea f-model></textarea>
    </u-field>
    <u-submit>Submit</u-submit>
  </u-form>
</template>

说明

  • :rules 对象用于向 注册自定义函数(键名与 validation 中的规则名一致)。
  • 规则函数第一个参数是 FieldNode,可以通过 node.value.value 访问当前值;随后的参数对应 validation 中传入的参数。

f-model 与 vite 插件说明

f-model 是一个语法糖,由 @vue-uform/vite-plugin 在编译阶段将简写转换为标准绑定。常见转换示例:

  • 普通输入:
<input f-model />

→ 编译为:

<input :value="value" @input="$event => update($event.target.value)" />

HTML 结构 / 布局可以自定义

vue-uform 的一大卖点是 完全可定制的字段结构。你可以:

  • 在单个 中通过 custom + slot 自定义 HTML;

  • 通过 scheme(传入一个 render function)为整个表单统一应用一种字段结构;

  • 用 CSS / 自定义组件将字段统一样式化(例如将 label 放在左边、错误信息下方显示等)。

下面详细说明每种方式并给出示例。


方式一:使用

slot

自定义单字段结构

在 使用 v-slot 并传入 custom(或直接自定义 slot 内容)即可:

<template>
  <u-form>
    <u-field name="username" v-slot="{ value, update, messages, label, help }" custom>
      <div class="my-field">
        <label class="my-label">{{ label }}</label>
        <div class="my-input-wrap">
          <input f-model />
        </div>
        <div class="my-help">{{ help }}</div>
        <ul class="my-errors">
          <li v-for="err in messages" :key="err">{{ err }}</li>
        </ul>
      </div>
    </u-field>

    <u-submit>Submit</u-submit>
  </u-form>
</template>

说明

  • v-slot 中通常会暴露 value, update, messages, label, help 等属性(具体字段名以库的实现为准)。
  • custom 属性(或某个布尔 prop)用于告诉组件你要完全接管渲染(避免内部重复渲染默认结构)。

方式二:通过 scheme(render function)为所有字段统一应用结构

当你想让表单中 所有 字段共享一个统一结构(同样样式、相同 DOM 布局)时,可以在 <u-form> 上传入 scheme。scheme 是一个接收参数并返回 h(...) 的函数(render function)。

示例(TypeScript):

<script setup lang="ts">
import { h } from 'vue'
import { SchemeArg } from 'vue-uform' // 假设库导出了类型

const myScheme = (arg: SchemeArg) => {
  // arg.slot() 是渲染字段 input 部分的函数
  // arg.label / arg.help / arg.errors 是可用的属性
  return h('div', { class: 'scheme-field' }, [
    h('label', { class: 'scheme-label' }, arg.label),
    h('div', { class: 'scheme-input' }, [arg.slot()]),
    arg.help ? h('div', { class: 'scheme-help' }, arg.help) : null,
    arg.messages && arg.messages.length
      ? h('ul', { class: 'scheme-errors' }, arg.messages.map((e: string) => h('li', e)))
      : null,
  ])
}
</script>

<template>
  <u-form :scheme="myScheme" :values="{ username: '' }">
    <u-field name="username" label="Username" validation="required">
      <input f-model />
    </u-field>
    <u-submit>Save</u-submit>
  </u-form>
</template>

说明

  • arg.slot() 用来插入 field 内部的 input/textarea/组件部分(由你在 的 slot 提供)。
  • scheme 统一了 DOM 结构与样式类,适合全局风格一致的需求。
  • 使用 h 可以自由组合任意 DOM 与 Vue 组件。

联系我们 / 贡献