String

View source
String 字段类型的使用方法和配置选项

基础用法

使用 afz.string() 创建字符串字段:

Input

Input 组件文档

基础输入框,通过 controlProps 配置图标、颜色等属性:

支持图标、颜色等配置
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  text: afz.string({
    controlProps: {
      icon: 'i-lucide-text'
    }
  })
    .min(3, '至少 3 个字符')
    .max(20, '最多 20 个字符')
    .meta({
      label: '基础输入框',
      placeholder: '请输入文本',
      hint: '支持图标、颜色等配置'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

Textarea

Textarea 组件文档

多行文本输入,设置 type: 'textarea',支持自动调整高度:

自动调整高度,最多 8 行
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  description: afz.string({
    type: 'textarea',
    controlProps: {
      maxrows: 4,
      autoresize: true
    }
  })
    .min(10, '至少 10 个字符')
    .meta({
      label: '文本域',
      placeholder: '请输入多行文本...',
      hint: '自动调整高度,最多 8 行'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

WithClear

输入内容后显示清除按钮,设置 type: 'withClear':

点击清除图标快速清空内容
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  search: afz.string({
    type: 'withClear',
    controlProps: {
      icon: 'i-lucide-search'
    }
  })
    .meta({
      label: '带清除按钮',
      placeholder: '输入内容后显示清除按钮',
      hint: '点击清除图标快速清空内容'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

WithPasswordToggle

密码输入框,可切换显示/隐藏,设置 type: 'withPasswordToggle':

点击眼睛图标切换显示/隐藏
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  password: afz.string({
    type: 'withPasswordToggle'
  })
    .min(8, '密码至少 8 个字符')
    .meta({
      label: '密码切换',
      placeholder: '请输入密码',
      hint: '点击眼睛图标切换显示/隐藏'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

WithCopy

点击复制按钮快速复制内容,设置 type: 'withCopy':

点击复制图标快速复制到剪贴板
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  apiKey: afz.string({
    type: 'withCopy'
  })
    .meta({
      label: '带复制按钮',
      placeholder: '输入内容后可复制',
      hint: '点击复制图标快速复制到剪贴板'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

WithCharacterLimit

实时显示剩余字符数,设置 type: 'withCharacterLimit':

实时显示剩余字符数
0/50
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  title: afz.string({
    type: 'withCharacterLimit',
    controlProps: {
      maxlength: 50
    }
  })
    .max(50, '最多 50 个字符')
    .meta({
      label: '字符限制',
      placeholder: '请输入标题',
      hint: '实时显示剩余字符数'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

PinInput

PinInput 组件文档

验证码或 PIN 码输入,设置 type: 'pinInput':

输入 6 位验证码
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  code: afz.string({
    type: 'pinInput',
    controlProps: {
      length: 6,
      mask: false
    }
  })
    .length(6, '请输入 6 位验证码')
    .meta({
      label: '验证码输入',
      hint: '输入 6 位验证码'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

InputMenu

InputMenu 组件文档

支持输入和下拉选择,设置 type: 'inputMenu':

支持输入和下拉选择
<script lang="ts" setup>
import type { FormSubmitEvent, InputMenuItem } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const items = [
  { label: 'Apple', value: 'apple' },
  { label: 'Banana', value: 'banana' },
  { label: 'Orange', value: 'orange' },
  { label: 'Grape', value: 'grape' }
] satisfies InputMenuItem[]

const schema = afz.object({
  fruit: afz.string({
    type: 'inputMenu',
    controlProps: {
      items,
      valueKey: 'value'
    }
  })
    .meta({
      label: '输入菜单',
      placeholder: '输入或选择水果',
      hint: '支持输入和下拉选择'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

ColorChooser

颜色选择器,支持可视化颜色选择和格式化,设置 type: 'colorChooser'

<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  color: afz.string({
    type: 'colorChooser',
    controlProps: {
      format: 'rgb'
    }
  })
    .meta({
      label: '颜色选择器',
      placeholder: '选择颜色'
    })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <MAutoForm :schema="schema" @submit="onSubmit" />
</template>

字符串格式验证

Zod v4 提供了专用的字符串验证方法:
Zod v4 迁移提示Zod v4 移除了 z.string().email() 等方法,改为专用函数:
// ❌ Zod v3 写法(已废弃)
z.string().email()

// ✅ Zod v4 正确写法
afz.email()

示例

动态类型

通过交互式示例探索字符串字段的各种类型和配置选项,包括:普通输入框、文本域、密码切换、清除按钮、复制功能、字符限制等增强功能,以及尺寸、颜色、行数等样式配置。

0/20
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type z from 'zod/v4'

const props = defineProps<{
  type: 'string' | 'textarea' | 'withPasswordToggle' | 'withClear' | 'withCopy' | 'withCharacterLimit'
  size: 'sm' | 'xs' | 'md' | 'lg' | 'xl'
  color: 'error' | 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'neutral'
  rows?: number
  maxLength?: number
}>()

const { afz } = useAutoForm()
const toast = useToast()

const schema = computed(() => (afz.object({
  stringWithType: afz.string({
    type: props.type,
    controlProps: {
      leadingIcon: 'i-lucide-type',
      color: props.color,
      rows: props.rows,
      maxLength: props.maxLength
    }
  }).meta({
    size: props.size
  })
})))

type Schema = z.output<typeof schema.value>

const form = ref<Partial<Schema>>({})

async function onSubmit(event: FormSubmitEvent<Schema>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

<template>
  <UCard class="w-lg">
    <MAutoForm
      :schema="schema"
      :state="form"
      :submit-button-props="{
        color
      }"
      @submit="onSubmit"
    />
  </UCard>
</template>

异步验证

使用 .refine() 方法配合异步函数实现服务端验证,例如检查用户名或邮箱是否已被占用:

admin, user, test (已被占用)
admin@example.com (已被注册)
<script lang="ts" setup>
import { sleep } from '@movk/core'
import type { FormSubmitEvent } from '@nuxt/ui'
import type z from 'zod/v4'

const { afz } = useAutoForm()
const toast = useToast()

const takenUsernames = ['admin', 'user', 'test', 'demo', 'root']

async function checkUsernameAvailability(username: string): Promise<boolean> {
  await sleep(1000)

  return !takenUsernames.includes(username.toLowerCase())
}

const schema = afz.object({
  username: afz.string()
    .min(3, '用户名至少需要 3 个字符')
    .max(20, '用户名最多 20 个字符')
    .regex(/^\w+$/, '只能包含字母、数字和下划线')
    .refine(
      async (username) => {
        return await checkUsernameAvailability(username)
      },
      '该用户名已被使用'
    )
    .meta({
      label: '用户名',
      placeholder: '请输入用户名',
      hint: 'admin, user, test (已被占用)'
    }).default('admin'),

  email: afz.email('请输入有效的邮箱地址')
    .refine(
      async (email) => {
        await sleep(800)
        const takenEmails = ['admin@example.com', 'test@example.com']
        return !takenEmails.includes(email.toLowerCase())
      },
      '该邮箱已被注册'
    )
    .meta({
      label: '邮箱',
      placeholder: 'your@email.com',
      hint: 'admin@example.com (已被注册)'
    }).default('admin@example.com')
})

type Schema = z.output<typeof schema>

const form = ref<Partial<Schema>>({})

async function onSubmit(event: FormSubmitEvent<Schema>) {
  toast.add({
    title: '验证通过',
    color: 'success',
    description: `用户名: ${event.data.username}\n邮箱: ${event.data.email}`
  })
}
</script>

<template>
  <UCard>
    <MAutoForm
      ref="autoFormRef"
      :schema="schema"
      :state="form"
      @submit="onSubmit"
    />
  </UCard>
</template>
Copyright © 2025 - 2025 YiXuan - MIT License