表单
Input OTP 验证码输入
用于验证码输入场景的 MoriUI 组件。
资源
导入
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from 'moriui'组合方式
InputOTP 基于 Reka PinInput,按索引组合 Slot,并可用 Group 与 Separator 建立视觉分段。
输入类型
MoriUI 使用 type="number" 限制数字,使用 type="text" 接受字母数字;不公开 input-otp 的 pattern/maxLength 字符串 API。
受控状态
v-model 是 string[] 或 number[];每个 InputOTPSlot 的 index 决定对应数组位置。
无效与禁用
disabled 设置在 InputOTP 根;无效样式和辅助技术状态设置在各 InputOTPSlot 的 aria-invalid。
RTL
dir 由 Reka UI 用于左右方向键顺序和输入组阅读方向。
示例
概览
六位数字验证码。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSlot } from 'moriui'
const code = ref<number[]>([1, 2, 3, 4, 5, 6])
</script>
<template>
<InputOTP v-model="code" type="number" aria-label="六位验证码">
<InputOTPGroup><InputOTPSlot v-for="index in 6" :key="index" :index="index - 1" /></InputOTPGroup>
</InputOTP>
</template>
仅数字
type="number" 过滤非数字输入。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSlot } from 'moriui'
const code = ref<number[]>([])
</script>
<template>
<InputOTP id="digits-only" v-model="code" type="number">
<InputOTPGroup><InputOTPSlot v-for="index in 6" :key="index" :index="index - 1" /></InputOTPGroup>
</InputOTP>
</template>
分隔符
Group 与 Separator 将验证码分段。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from 'moriui'
const code = ref<string[]>([])
</script>
<template>
<InputOTP v-model="code" aria-label="分组验证码">
<InputOTPGroup><InputOTPSlot :index="0" /><InputOTPSlot :index="1" /></InputOTPGroup><InputOTPSeparator /><InputOTPGroup><InputOTPSlot :index="2" /><InputOTPSlot :index="3" /></InputOTPGroup><InputOTPSeparator /><InputOTPGroup><InputOTPSlot :index="4" /><InputOTPSlot :index="5" /></InputOTPGroup>
</InputOTP>
</template>
禁用
disabled 阻止所有验证码格交互。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSlot } from 'moriui'
const code = ref<number[]>([1, 2, 3, 4, 5, 6])
</script>
<template>
<InputOTP
v-model="code"
disabled
type="number"
aria-label="禁用验证码"
>
<InputOTPGroup><InputOTPSlot v-for="index in 6" :key="index" :index="index - 1" /></InputOTPGroup>
</InputOTP>
</template>
受控
数组 v-model 实时展示当前值。
请输入一次性验证码。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSlot } from 'moriui'
const code = ref<number[]>([])
</script>
<template>
<div class="space-y-2">
<InputOTP v-model="code" type="number" aria-label="受控验证码">
<InputOTPGroup><InputOTPSlot v-for="index in 6" :key="index" :index="index - 1" /></InputOTPGroup>
</InputOTP><p class="text-center text-sm">
{{ code.length ? `已输入:${code.join('')}` : '请输入一次性验证码。' }}
</p>
</div>
</template>
无效
每个 Slot 使用 aria-invalid。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSlot } from 'moriui'
const code = ref<number[]>([0, 0, 0, 0, 0, 0])
</script>
<template>
<InputOTP v-model="code" type="number" aria-label="无效验证码">
<InputOTPGroup>
<InputOTPSlot
v-for="index in 6"
:key="index"
:index="index - 1"
aria-invalid="true"
/>
</InputOTPGroup>
</InputOTP>
</template>
四位 PIN
四个索引组成常见 PIN 输入。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSlot } from 'moriui'
const code = ref<number[]>([])
</script>
<template>
<InputOTP v-model="code" type="number" aria-label="四位 PIN">
<InputOTPGroup><InputOTPSlot v-for="index in 4" :key="index" :index="index - 1" /></InputOTPGroup>
</InputOTP>
</template>
字母数字
type="text" 接受字母与数字。
<script setup lang="ts">
import { ref } from 'vue'
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from 'moriui'
const code = ref<string[]>([])
</script>
<template>
<InputOTP v-model="code" type="text" aria-label="字母数字验证码">
<InputOTPGroup><InputOTPSlot v-for="index in 3" :key="index" :index="index - 1" /></InputOTPGroup><InputOTPSeparator /><InputOTPGroup><InputOTPSlot v-for="index in 3" :key="index + 3" :index="index + 2" /></InputOTPGroup>
</InputOTP>
</template>
表单
验证卡片组合标签、重发与提交操作。
验证登录
输入发送到 [email protected] 的验证码。
无法访问邮箱?请联系支持团队。
<script setup lang="ts">
import { ref } from 'vue'
import { RefreshCw } from '@lucide/vue'
import {
Button,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Field,
FieldDescription,
FieldLabel,
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot
} from 'moriui'
const code = ref<number[]>([])
</script>
<template>
<Card class="w-full max-w-md">
<CardHeader><CardTitle>验证登录</CardTitle><CardDescription>输入发送到 [email protected] 的验证码。</CardDescription></CardHeader><CardContent>
<Field>
<div class="flex items-center justify-between">
<FieldLabel for="verification-code">
验证码
</FieldLabel><Button size="xs" variant="outline">
<RefreshCw />重新发送
</Button>
</div><InputOTP
id="verification-code"
v-model="code"
required
type="number"
>
<InputOTPGroup><InputOTPSlot v-for="index in 3" :key="index" :index="index - 1" /></InputOTPGroup><InputOTPSeparator /><InputOTPGroup><InputOTPSlot v-for="index in 3" :key="index + 3" :index="index + 2" /></InputOTPGroup>
</InputOTP><FieldDescription>无法访问邮箱?请联系支持团队。</FieldDescription>
</Field>
</CardContent><CardFooter>
<Button class="w-full" type="submit">
验证
</Button>
</CardFooter>
</Card>
</template>
RTL
验证码在 RTL 方向中保持正确键盘顺序。
<script setup lang="ts">
import { ref } from 'vue'
import { Field, FieldLabel, InputOTP, InputOTPGroup, InputOTPSlot } from 'moriui'
const code = ref<number[]>([1, 2, 3, 4, 5, 6])
</script>
<template>
<Field dir="rtl" class="w-full max-w-xs">
<FieldLabel for="otp-rtl">
رمز التحقق
</FieldLabel><InputOTP
id="otp-rtl"
v-model="code"
dir="rtl"
type="number"
>
<InputOTPGroup><InputOTPSlot v-for="index in 6" :key="index" :index="index - 1" /></InputOTPGroup>
</InputOTP>
</Field>
</template>
API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| InputOTP v-model | string[] | number[] | [] | 按 Slot index 排列的验证码值。 |
| InputOTP type | 'text' | 'number' | 'text' | 文本或数字输入模式,并决定 v-model 数组类型。 |
| InputOTP otp | boolean | true | 启用一次性验证码自动填充与顺序输入。 |
| InputOTP disabled / required | boolean | false | 整体禁用与表单必填语义。 |
| InputOTP mask | boolean | false | 以密码形式隐藏每格内容。 |
| InputOTP @complete | (value: string[] | number[]) => void | — | 所有已渲染 Slot 填满时触发。 |
| InputOTPSlot index | number | — | 必填的数组位置。 |
无障碍说明
InputOTP 复用 Reka PinInput 的粘贴分发、自动前进、退格、方向键与隐藏表单输入。根组件需要标签或 aria-label;禁用设置在根,无效状态设置在对应 Slot,并提供可读错误说明。