<script setup lang="ts">
import { ref } from 'vue'
import { TagsInput } from '@hina-ui/vue'
const tags = ref(['Galgame', '轻小说'])
</script>
<template>
<TagsInput v-model="tags" placeholder="添加标签" aria-label="作品标签" class="max-w-sm" />
</template>
vue
用法
import { TagsInput } from '@hina-ui/vue'
ts
标签输入框在一个输入面里保存多个值,每个值显示为一个可移除的标签。v-model 绑定字符串数组。在输入区输入文字后按 Enter,或者输入分隔符,文字就会添加为标签;标签一行放不下时,输入面的高度随之增加。未声明的属性都会传给内部的文本输入,请用 aria-label 或者 aria-labelledby 命名。
还没有标签
<script setup lang="ts">
import { ref } from 'vue'
import { Stack, TagsInput, Text } from '@hina-ui/vue'
const tags = ref<string[]>([])
</script>
<template>
<Stack gap="sm" class="w-full max-w-sm">
<TagsInput v-model="tags" placeholder="输入后按 Enter" aria-label="关键词" />
<Text tone="muted" size="sm">{{ tags.length ? tags.join('、') : '还没有标签' }}</Text>
</Stack>
</template>
vue
它与 MultiSelect 的区别在于值的来源:多选选择器从给定的选项中挑选,标签输入框接受任意文字。
示例
数量上限与重复
max 限制标签数量,duplicate 决定是否允许重复。被拒绝的输入会触发 invalid 事件,参数是被拒绝的文字。
最多三个,不允许重复
<script setup lang="ts">
import { ref } from 'vue'
import { Stack, TagsInput, Text } from '@hina-ui/vue'
const tags = ref(['日常', '恋爱'])
const rejected = ref('')
</script>
<template>
<Stack gap="sm" class="w-full max-w-sm">
<TagsInput
v-model="tags"
:max="3"
placeholder="最多三个"
aria-label="题材"
@invalid="rejected = $event"
/>
<Text tone="muted" size="sm">
{{ rejected ? `「${rejected}」未加入` : '最多三个,不允许重复' }}
</Text>
</Stack>
</template>
vue
分隔符与粘贴
delimiter 默认为逗号,可以换成其他字符或者正则表达式。addOnPaste 默认开启,粘贴的文字按分隔符拆分为多个标签;addOnBlur 让输入区失去焦点时也把剩余文字添加为标签。
<script setup lang="ts">
import { ref } from 'vue'
import { TagsInput } from '@hina-ui/vue'
const tags = ref<string[]>([])
</script>
<template>
<TagsInput
v-model="tags"
delimiter=" "
add-on-blur
placeholder="以空格分隔,可以整段粘贴"
aria-label="别名"
class="max-w-sm"
/>
</template>
vue
可清空
clearable 在末尾显示清除按钮,一次移除全部标签,并触发 clear 事件。
<script setup lang="ts">
import { ref } from 'vue'
import { TagsInput } from '@hina-ui/vue'
const tags = ref(['Key', 'Type-Moon', 'Nitroplus'])
</script>
<template>
<TagsInput
v-model="tags"
clearable
placeholder="添加制作公司"
aria-label="制作公司"
class="max-w-sm"
/>
</template>
vue
尺寸
size 有 sm、md、lg 三档,没有标签时的高度与同档输入框相等。
<script setup lang="ts">
import { Stack, TagsInput } from '@hina-ui/vue'
</script>
<template>
<Stack gap="sm" class="w-full max-w-sm">
<TagsInput size="sm" :model-value="['小号']" aria-label="小号" />
<TagsInput size="md" :model-value="['中号']" aria-label="中号" />
<TagsInput size="lg" :model-value="['大号']" aria-label="大号" />
</Stack>
</template>
vue
状态
invalid 给输入面加上警示色,disabled 禁用整组,标签不可移除。variant="secondary" 是放在 surface 之内的扁平形态。
<script setup lang="ts">
import { Stack, TagsInput } from '@hina-ui/vue'
</script>
<template>
<Stack gap="sm" class="w-full max-w-sm">
<TagsInput :model-value="['校验未通过']" invalid aria-label="校验未通过" />
<TagsInput :model-value="['已禁用']" disabled aria-label="已禁用" />
<TagsInput :model-value="['扁平形态']" variant="secondary" aria-label="扁平形态" />
</Stack>
</template>
vue
在表单中
放进 FormField 后,标签指向输入区,说明与错误信息由字段渲染;校验规则与提交交给 Form。值是字符串数组,数量与单个标签的长度分别写在数组层与元素层。
<script setup lang="ts">
import { reactive, ref } from 'vue'
import * as v from 'valibot'
import { Button, Form, FormField, TagsInput, Text } from '@hina-ui/vue'
const schema = v.object({
aliases: v.pipe(
v.array(v.pipe(v.string(), v.maxLength(20, '别名不超过 20 个字'))),
v.minLength(1, '至少填写一个别名'),
v.maxLength(5, '最多五个别名'),
),
})
const values = reactive({ aliases: [] as string[] })
const saved = ref('')
async function save(data: unknown) {
await new Promise(resolve => setTimeout(resolve, 600))
saved.value = JSON.stringify(data)
}
</script>
<template>
<Form v-slot="{ submitting }" :values="values" :rules="schema" class="w-80" @submit="save">
<FormField name="aliases" label="别名" description="回车添加,最多五个" required>
<TagsInput v-model="values.aliases" />
</FormField>
<Button type="submit" :loading="submitting" class="self-start">保存</Button>
<Text v-if="saved" tone="muted" size="sm">已保存:{{ saved }}</Text>
</Form>
</template>
vue
行为
- 按 Enter 或者输入分隔符,把当前文字添加为标签并清空输入区。
- 输入区为空时按退格移除末尾的标签。
- 点击标签或者输入面的空白处即聚焦输入区。
- 每个标签末尾有移除按钮,点击即移除。
- 超过
max或者重复的值不会加入,触发invalid。
无障碍
- 文本输入通过
aria-label或者aria-labelledby命名,未声明的属性都会传给它。 - 每个标签的移除按钮带有语言包给出的名称。
invalid会同时在文本输入上设置aria-invalid。
API
Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | string[] | [] | 标签列表 |
placeholder | string | — | 输入区的占位文字 |
max | number | 0 | 标签数量上限, 0 表示不限 |
duplicate | boolean | false | 是否允许重复的标签 |
delimiter | string | RegExp | ',' | 分隔符 |
addOnPaste | boolean | true | 粘贴时是否按分隔符拆分为标签 |
addOnBlur | boolean | false | 失去焦点时是否把剩余文字添加为标签 |
clearable | boolean | false | 是否显示清除按钮 |
name | string | — | 表单字段名 |
variant | 'primary' | 'secondary' | 'primary' | 形态 |
size | 'sm' | 'md' | 'lg' | 'md' | 尺寸 |
disabled | boolean | false | 是否禁用 |
invalid | boolean | false | 是否处于校验未通过状态 |
class | string | — | 追加至根元素的类名 |
事件
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: string[] | 标签列表变化 |
invalid | value: string | 输入被拒绝 |
clear | — | 全部清空 |