表单
Field 表单字段
用于表单字段场景的 MoriUI 组件。
资源
导入
import { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle } from 'moriui'组合方式
单个 Field 组合 Label、控件、Description 与 Error;相关控件由 FieldGroup 和语义 FieldSet 组织。
结构
FieldContent 用于横向布局中的标题与说明;没有说明时不需要额外包装。
响应式布局
orientation 支持 vertical、horizontal、responsive;responsive 通过组件样式在合适容器宽度切换。
校验与错误
Field 使用 data-invalid,真实控件使用 aria-invalid,FieldError 以 role="alert" 输出去重后的错误。
示例
概览
组合字段组、字段集、分隔线与操作。
<script setup lang="ts">
import { shallowRef } from 'vue'
import {
Button,
Checkbox,
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSeparator,
FieldSet,
Input
} from 'moriui'
const sameAddress = shallowRef(true)
</script>
<template>
<form class="w-full max-w-md">
<FieldGroup>
<FieldSet>
<FieldLegend>付款信息</FieldLegend>
<FieldDescription>所有交易均经过加密。</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel for="card-name">
持卡人
</FieldLabel><Input id="card-name" required placeholder="林晓" />
</Field>
<Field>
<FieldLabel for="card-number">
卡号
</FieldLabel><Input
id="card-number"
required
inputmode="numeric"
placeholder="1234 5678 9012 3456"
/><FieldDescription>请输入 16 位卡号。</FieldDescription>
</Field>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<Field orientation="horizontal">
<Checkbox id="same-address" v-model="sameAddress" /><FieldLabel for="same-address">
账单地址与收货地址相同
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Button type="submit">
提交
</Button><Button type="button" variant="outline">
取消
</Button>
</Field>
</FieldGroup>
</form>
</template>
输入框
标签、输入和说明的基础字段。
<script setup lang="ts">
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldSet,
Input
} from 'moriui'
</script>
<template>
<FieldSet class="w-full max-w-xs">
<FieldGroup>
<Field>
<FieldLabel for="username">
用户名
</FieldLabel><Input id="username" placeholder="Mori" /><FieldDescription>请选择唯一的用户名。</FieldDescription>
</Field>
<Field>
<FieldLabel for="password">
密码
</FieldLabel><FieldDescription>至少包含 8 个字符。</FieldDescription><Input id="password" type="password" placeholder="••••••••" />
</Field>
</FieldGroup>
</FieldSet>
</template>
多行输入
Textarea 与帮助文字组成反馈字段。
请描述遇到的问题或建议。
<script setup lang="ts">
import { Field, FieldDescription, FieldLabel, Textarea } from 'moriui'
</script>
<template>
<Field class="w-full max-w-xs">
<FieldLabel for="feedback">
反馈
</FieldLabel><Textarea id="feedback" rows="4" placeholder="你的建议会帮助我们改进…" /><FieldDescription>请描述遇到的问题或建议。</FieldDescription>
</Field>
</template>
选择框
MoriUI Select 可复用 Field 的标签、说明与布局。
选择你的工作部门。
<script setup lang="ts">
import { shallowRef } from 'vue'
import {
Field,
FieldDescription,
FieldLabel,
Select,
SelectContent,
SelectItem,
SelectItemIndicator,
SelectItemText,
SelectTrigger,
SelectValue,
SelectViewport
} from 'moriui'
const department = shallowRef<string>()
</script>
<template>
<Field class="w-full max-w-xs">
<FieldLabel for="department">
部门
</FieldLabel>
<Select v-model="department">
<SelectTrigger id="department" aria-label="部门">
<SelectValue placeholder="选择部门" />
</SelectTrigger>
<SelectContent>
<SelectViewport>
<SelectItem v-for="item in ['工程', '设计', '市场']" :key="item" :value="item">
<SelectItemIndicator /><SelectItemText>{{ item }}</SelectItemText>
</SelectItem>
</SelectViewport>
</SelectContent>
</Select>
<FieldDescription>选择你的工作部门。</FieldDescription>
</Field>
</template>
滑块
标题与说明展示当前范围值。
预算范围
当前预算:¥500
<script setup lang="ts">
import { shallowRef } from 'vue'
import {
Field,
FieldDescription,
FieldTitle,
Slider,
SliderRange,
SliderThumb,
SliderTrack
} from 'moriui'
const budget = shallowRef([500])
</script>
<template>
<Field class="w-full max-w-xs">
<FieldTitle>预算范围</FieldTitle>
<FieldDescription>当前预算:¥{{ budget[0] }}</FieldDescription>
<Slider
v-model="budget"
:min="0"
:max="1000"
:step="10"
aria-label="预算范围"
>
<SliderTrack><SliderRange /></SliderTrack><SliderThumb />
</Slider>
</Field>
</template>
字段集
FieldSet 与 Legend 建立语义分组。
<script setup lang="ts">
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
Input
} from 'moriui'
</script>
<template>
<FieldSet class="w-full max-w-sm">
<FieldLegend>地址信息</FieldLegend><FieldDescription>我们需要地址来配送订单。</FieldDescription><FieldGroup>
<Field>
<FieldLabel for="street">
街道地址
</FieldLabel><Input id="street" placeholder="中山路 123 号" />
</Field>
<div class="grid grid-cols-2 gap-4">
<Field>
<FieldLabel for="city">
城市
</FieldLabel><Input id="city" placeholder="上海" />
</Field><Field>
<FieldLabel for="postal">
邮编
</FieldLabel><Input id="postal" placeholder="200000" />
</Field>
</div>
</FieldGroup>
</FieldSet>
</template>
复选框
多个复选字段共享说明和图例。
<script setup lang="ts">
import { ref } from 'vue'
import {
Checkbox,
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet
} from 'moriui'
const items = ref({ disk: true, server: false })
</script>
<template>
<FieldSet class="w-full max-w-xs">
<FieldLegend variant="label">
桌面项目
</FieldLegend><FieldDescription>选择要显示的项目。</FieldDescription><FieldGroup>
<Field orientation="horizontal">
<Checkbox id="disk" v-model="items.disk" /><FieldLabel for="disk">
硬盘
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="server" v-model="items.server" /><FieldLabel for="server">
已连接服务器
</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
</template>
单选
RadioGroup 与多个 RadioGroupItem 共享 Field 布局。
<script setup lang="ts">
import { shallowRef } from 'vue'
import {
Field,
FieldDescription,
FieldLabel,
FieldLegend,
FieldSet,
RadioGroup,
RadioGroupItem
} from 'moriui'
const plan = shallowRef('monthly')
</script>
<template>
<FieldSet class="w-full max-w-xs">
<FieldLegend variant="label">
订阅方案
</FieldLegend><FieldDescription>年付方案更优惠。</FieldDescription>
<RadioGroup v-model="plan">
<Field orientation="horizontal">
<RadioGroupItem id="monthly" value="monthly" /><FieldLabel for="monthly">
月付(¥68/月)
</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem id="yearly" value="yearly" /><FieldLabel for="yearly">
年付(¥680/年)
</FieldLabel>
</Field>
</RadioGroup>
</FieldSet>
</template>
开关
横向 Field 对齐标签与 Switch。
<script setup lang="ts">
import { shallowRef } from 'vue'
import { Field, FieldLabel, Switch } from 'moriui'
const enabled = shallowRef(false)
</script>
<template>
<Field class="w-fit" orientation="horizontal">
<FieldLabel for="two-factor">
多因素认证
</FieldLabel><Switch id="two-factor" v-model="enabled" />
</Field>
</template>
选择卡片
FieldLabel 包裹完整选择卡片。
<script setup lang="ts">
import { shallowRef } from 'vue'
import {
Field,
FieldContent,
FieldDescription,
FieldLabel,
FieldLegend,
FieldSet,
FieldTitle,
RadioGroup,
RadioGroupItem
} from 'moriui'
const environment = shallowRef('kubernetes')
</script>
<template>
<FieldSet class="w-full max-w-xs">
<FieldLegend variant="label">
计算环境
</FieldLegend>
<RadioGroup v-model="environment">
<FieldLabel for="kubernetes">
<Field orientation="horizontal">
<FieldContent><FieldTitle>Kubernetes</FieldTitle><FieldDescription>在 K8s 集群运行工作负载。</FieldDescription></FieldContent><RadioGroupItem id="kubernetes" value="kubernetes" />
</Field>
</FieldLabel>
<FieldLabel for="vm">
<Field orientation="horizontal">
<FieldContent><FieldTitle>虚拟机</FieldTitle><FieldDescription>使用独立虚拟机运行任务。</FieldDescription></FieldContent><RadioGroupItem id="vm" value="vm" />
</Field>
</FieldLabel>
</RadioGroup>
</FieldSet>
</template>
字段组
FieldSeparator 分隔通知类别。
<script setup lang="ts">
import { shallowRef } from 'vue'
import {
Checkbox,
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldSeparator,
FieldSet
} from 'moriui'
const taskEmail = shallowRef(false)
</script>
<template>
<FieldGroup class="w-full max-w-xs">
<FieldSet>
<FieldLabel>长任务</FieldLabel><FieldDescription>研究或图片生成完成时通知我。</FieldDescription><Field orientation="horizontal">
<Checkbox id="push" disabled :model-value="true" /><FieldLabel for="push">
推送通知
</FieldLabel>
</Field>
</FieldSet>
<FieldSeparator />
<FieldSet>
<FieldLabel>任务更新</FieldLabel><FieldDescription>任务状态变化时通知我。</FieldDescription><Field orientation="horizontal">
<Checkbox id="task-email" v-model="taskEmail" /><FieldLabel for="task-email">
邮件通知
</FieldLabel>
</Field>
</FieldSet>
</FieldGroup>
</template>
RTL
字段结构继承 RTL 文本方向。
<script setup lang="ts">
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
Input
} from 'moriui'
</script>
<template>
<FieldSet dir="rtl" class="w-full max-w-sm">
<FieldLegend>معلومات الدفع</FieldLegend><FieldDescription>جميع المعاملات آمنة ومشفرة.</FieldDescription><FieldGroup>
<Field>
<FieldLabel for="rtl-name">
الاسم على البطاقة
</FieldLabel><Input id="rtl-name" dir="rtl" required />
</Field>
</FieldGroup>
</FieldSet>
</template>
响应式
responsive 在容器中调整标签与控件布局。
<script setup lang="ts">
import {
Button,
Field,
FieldContent,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
Input
} from 'moriui'
</script>
<template>
<form class="w-full max-w-lg">
<FieldSet>
<FieldLegend>个人资料</FieldLegend><FieldDescription>填写你的公开资料。</FieldDescription><FieldGroup>
<Field orientation="responsive">
<FieldContent>
<FieldLabel for="profile-name">
姓名
</FieldLabel><FieldDescription>用于团队协作中的身份识别。</FieldDescription>
</FieldContent><Input id="profile-name" required placeholder="林晓" />
</Field>
<Field orientation="responsive">
<Button type="submit">
提交
</Button><Button type="button" variant="outline">
取消
</Button>
</Field>
</FieldGroup>
</FieldSet>
</form>
</template>
API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| Field orientation | 'vertical' | 'horizontal' | 'responsive' | 'vertical' | 标签、控件和说明的布局方向。 |
| FieldLegend variant | 'legend' | 'label' | 'legend' | 语义图例的视觉层级。 |
| FieldError errors | Array<string | { message?: string } | null | undefined> | [] | 去重并渲染一个或多个错误消息。 |
| FieldLabel | LabelProps | — | 完整透传 MoriUI Label 属性。 |
| class | HTMLAttributes["class"] | undefined | 所有 Field 子组件均合并调用方类。 |
无障碍说明
FieldSet 与 FieldLegend 提供原生字段集语义,Field 输出 role="group",FieldError 输出 role="alert"。Label 的 for 必须指向控件 id;无效控件同时使用 aria-invalid 与可读错误消息。