六维教程

表单与输入

表单是业务系统里最重的部分。Nuxt UI 把输入框、下拉、开关等控件,连同「字段标签、校验、错误提示」一起打包成 UForm + UFormField + 各种输入组件,写起来比裸表单省很多事。

本篇基于 /453.html 接好的环境,重点讲怎么搭一个带校验的表单。

整体结构

UForm 是表单容器,UFormField 包住单个字段(负责标签和错误信息),里面再放具体输入组件(如 UInput)。

<template>
  <UForm :state="state" :validate="validate" @submit="onSubmit">
    <UFormField name="email" label="邮箱">
      <UInput v-model="state.email" placeholder="you@example.com" />
    </UFormField>

    <UButton type="submit" class="mt-4">提交</UButton>
  </UForm>
</template>

<script setup>
const state = reactive({
  email: ''
})

function validate(state) {
  const errors = []
  if (!state.email) {
    errors.push({ name: 'email', message: '邮箱不能为空' })
  }
  return errors
}

function onSubmit() {
  console.log('提交的数据', state)
}
</script>

几个要点。

  • :state 是表单数据对象,字段用 v-model 双向绑定。
  • :validate 是一个函数,返回「错误数组」,每项含 name(对应 UFormFieldname)和 message
  • @submit 在「校验通过」后触发;校验没过不会提交。
  • UButtontype="submit" 会让它成为提交按钮(按钮 UButton 里讲过)。

常用输入组件

除了 UInput,Nuxt UI 还有一组输入控件,用法都类似,都是 v-model 绑定值。

<template>
  <UForm :state="state" @submit="onSubmit">
    <UFormField name="name" label="姓名">
      <UInput v-model="state.name" />
    </UFormField>

    <UFormField name="bio" label="简介">
      <UTextarea v-model="state.bio" />
    </UFormField>

    <UFormField name="role" label="角色">
      <USelect v-model="state.role" :items="['管理员', '普通用户']" />
    </UFormField>

    <UFormField name="notify" label="接收通知">
      <USwitch v-model="state.notify" />
    </UFormField>

    <UFormField name="agree" label="同意条款">
      <UCheckbox v-model="state.agree" label="我已阅读并同意" />
    </UFormField>

    <UButton type="submit" class="mt-4">提交</UButton>
  </UForm>
</template>

<script setup>
const state = reactive({
  name: '',
  bio: '',
  role: undefined,
  notify: false,
  agree: false
})

function onSubmit() {
  console.log(state)
}
</script>

USelect:items 传选项数组;USwitchUCheckbox 绑定布尔值。UFormFieldlabel 会自动渲染成字段标题。

用 zod 做校验

上面的 :validate 是手写判断,字段多了会啰嗦。Nuxt UI 支持传 :schema(用 zod 定义),校验规则集中写好,错误信息也能自动生成。

npm install zod
<template>
  <UForm :schema="schema" :state="state" @submit="onSubmit">
    <UFormField name="email" label="邮箱">
      <UInput v-model="state.email" />
    </UFormField>
    <UButton type="submit" class="mt-4">提交</UButton>
  </UForm>
</template>

<script setup>
import { z } from 'zod'

const schema = z.object({
  email: z.string().email('请输入合法的邮箱')
})

const state = reactive({
  email: ''
})

function onSubmit() {
  console.log(state)
}
</script>

:schema:validate 二选一即可,新手推荐先用 :validate 手写,规则复杂了再上 zod。

提交中的加载态

提交按钮常常要在请求期间禁用并转圈,用 loading-auto 最省事(见 按钮 UButton)。

<template>
  <UForm :state="state" :validate="validate" @submit="onSubmit">
    <UFormField name="email" label="邮箱">
      <UInput v-model="state.email" />
    </UFormField>
    <UButton type="submit" loading-auto class="mt-4">提交</UButton>
  </UForm>
</template>

<script setup>
const state = reactive({ email: '' })

function validate(state) {
  const errors = []
  if (!state.email.includes('@')) {
    errors.push({ name: 'email', message: '邮箱格式不正确' })
  }
  return errors
}

// 返回 Promise,按钮会自动转圈直到它结束
function onSubmit() {
  return new Promise(resolve => setTimeout(resolve, 1000))
}
</script>

常见问题

问题 解决方法
错误信息不显示 确认 UFormFieldnamevalidate 返回的 name 一致
提交没反应 检查是否触发了校验失败(有错误时 @submit 不会执行)
USelect 不显示选项 确认 :items 传的是数组,且 v-model 初始值类型匹配

参考资料

上一篇
按钮 UButton
下一篇
卡片与容器