<script setup lang="ts">
import { ref } from 'vue'
import { Bold, Italic, Underline } from '@lucide/vue'
import { Inline, Toggle } from '@hina-ui/vue'
const bold = ref(true)
const italic = ref(false)
const underline = ref(false)
</script>
<template>
<Inline gap="xs">
<Toggle v-model="bold" label="加粗">
<template #icon><Bold /></template>
</Toggle>
<Toggle v-model="italic" label="斜体">
<template #icon><Italic /></template>
</Toggle>
<Toggle v-model="underline" label="下划线">
<template #icon><Underline /></template>
</Toggle>
</Inline>
</template>
vue
用法
import { Toggle } from '@hina-ui/vue'
ts
切换按钮是一个可以保持按下状态的按钮,用于加粗、收藏、筛选这类随时可以打开或者关闭的操作。v-model 绑定是否按下,默认插槽是文字,#icon 放前置图标。外观取自 Button 的 ghost 与 outline 两种形态,按下后字色与墨转为品牌色。未声明的属性都会传给按钮元素。
显示全部作品
<script setup lang="ts">
import { ref } from 'vue'
import { ListFilter } from '@lucide/vue'
import { Stack, Text, Toggle } from '@hina-ui/vue'
const onlyDone = ref(false)
</script>
<template>
<Stack gap="sm" align="start">
<Toggle v-model="onlyDone">
<template #icon><ListFilter /></template>
仅看已完结
</Toggle>
<Text tone="muted" size="sm">{{ onlyDone ? '只显示已完结的作品' : '显示全部作品' }}</Text>
</Stack>
</template>
vue
它与 Switch 的区别在于场合:开关表示一项设置,总是带文字说明,独立成行;切换按钮是一个动作,常常只有图标,成排出现在工具栏里。与 Chip 的可选中形态相比,Chip 是行内的条目,胶囊形且尺寸更小。
示例
图标型
label 提供无障碍名称。没有默认文字插槽时,按钮使用正方形的图标型尺寸;同时提供文字时,保留常规按钮内边距。在 TooltipProvider 内,label 还会作为 Tooltip 的文字提示。#pressed-icon 给出按下时的图标,两个图标之间交叉淡变。
<script setup lang="ts">
import { ref } from 'vue'
import { Bookmark, Star } from '@lucide/vue'
import { Inline, Toggle } from '@hina-ui/vue'
const starred = ref(true)
const saved = ref(false)
</script>
<template>
<Inline gap="xs">
<Toggle v-model="starred" label="收藏" pill>
<template #icon><Star /></template>
<template #pressed-icon><Star fill="currentColor" /></template>
</Toggle>
<Toggle v-model="saved" label="稍后再看" pill>
<template #icon><Bookmark /></template>
<template #pressed-icon><Bookmark fill="currentColor" /></template>
</Toggle>
</Inline>
</template>
vue
工具栏
成排的图标型切换按钮各自持有一个布尔值,互不影响。需要恰好一项被选中时应使用 SegmentedControl。
<script setup lang="ts">
import { reactive } from 'vue'
import { Bold, Italic, Strikethrough, Underline } from '@lucide/vue'
import { Inline, Toggle } from '@hina-ui/vue'
const marks = reactive({ bold: false, italic: false, underline: false, strike: false })
</script>
<template>
<Inline gap="xs">
<Toggle v-model="marks.bold" label="加粗" size="sm">
<template #icon><Bold /></template>
</Toggle>
<Toggle v-model="marks.italic" label="斜体" size="sm">
<template #icon><Italic /></template>
</Toggle>
<Toggle v-model="marks.underline" label="下划线" size="sm">
<template #icon><Underline /></template>
</Toggle>
<Toggle v-model="marks.strike" label="删除线" size="sm">
<template #icon><Strikethrough /></template>
</Toggle>
</Inline>
</template>
vue
形态
ghost 为默认,outline 带发丝线边框,适合单独放在内容里。
<script setup lang="ts">
import { ref } from 'vue'
import { Pin } from '@lucide/vue'
import { Inline, Toggle } from '@hina-ui/vue'
const ghost = ref(true)
const outline = ref(true)
</script>
<template>
<Inline gap="sm">
<Toggle v-model="ghost" variant="ghost">
<template #icon><Pin /></template>
置顶
</Toggle>
<Toggle v-model="outline" variant="outline">
<template #icon><Pin /></template>
置顶
</Toggle>
</Inline>
</template>
vue
尺寸
size 有 sm、md、lg 三档,与 Button 逐档相同。
<script setup lang="ts">
import { Heart } from '@lucide/vue'
import { Inline, Toggle } from '@hina-ui/vue'
</script>
<template>
<Inline gap="sm" align="center">
<Toggle size="sm" variant="outline" model-value>
<template #icon><Heart /></template>
小号
</Toggle>
<Toggle size="md" variant="outline" model-value>
<template #icon><Heart /></template>
中号
</Toggle>
<Toggle size="lg" variant="outline" model-value>
<template #icon><Heart /></template>
大号
</Toggle>
</Inline>
</template>
vue
状态
disabled 禁用按钮,禁用时保留按下状态。
<script setup lang="ts">
import { Bold } from '@lucide/vue'
import { Inline, Toggle } from '@hina-ui/vue'
</script>
<template>
<Inline gap="sm">
<Toggle variant="outline" disabled>
<template #icon><Bold /></template>
已禁用
</Toggle>
<Toggle variant="outline" disabled model-value>
<template #icon><Bold /></template>
禁用且按下
</Toggle>
</Inline>
</template>
vue
在表单中
放进 FormField 后,错误信息由字段渲染并关联到按钮;校验规则与提交交给 Form。切换按钮自带文字,字段不必再写标签;它的值决定其他字段是否必填时,规则写在对象层,再指定错误落在哪个字段。
<script setup lang="ts">
import { reactive, ref } from 'vue'
import * as v from 'valibot'
import { Button, Form, FormField, Input, Text, Toggle } from '@hina-ui/vue'
const schema = v.pipe(
v.object({
pinned: v.boolean(),
title: v.string(),
}),
v.forward(
v.check(input => !input.pinned || input.title.trim().length > 0, '置顶的公告需要标题'),
['title'],
),
)
const values = reactive({ pinned: true, title: '' })
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="title" label="标题">
<Input v-model="values.title" />
</FormField>
<FormField name="pinned">
<Toggle v-model="values.pinned" variant="outline">置顶</Toggle>
</FormField>
<Button type="submit" :loading="submitting" class="self-start">发布</Button>
<Text v-if="saved" tone="muted" size="sm">已发布:{{ saved }}</Text>
</Form>
</template>
vue
行为
- 点击、空格或者 Enter 在按下与松开之间切换。
- 按下态由品牌色的墨与字色表达,悬停与按压的墨叠加在其上。
- 有
#pressed-icon时两个图标交叉淡变,不硬切。
无障碍
- 根元素是带
aria-pressed的按钮,读屏软件读作「切换按钮,已按下」。 - 图标型必须提供
label;文字型默认以文字命名,也可通过label补充完整名称。
API
Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | boolean | false | 是否按下 |
label | string | — | 无障碍名称;无文字插槽时使用图标型尺寸 |
tooltip | boolean | true | 是否显示 label 对应的文字提示 |
side | 'top' | 'right' | 'bottom' | 'left' | 'top' | 文字提示的位置 |
variant | 'ghost' | 'outline' | 'ghost' | 形态 |
size | 'sm' | 'md' | 'lg' | 'md' | 尺寸 |
pill | boolean | false | 是否为胶囊形 |
disabled | boolean | false | 是否禁用 |
ripple | boolean | true | 是否显示按压波纹 |
class | string | — | 追加至按钮元素的类名 |
插槽
| 插槽 | 参数 | 说明 |
|---|---|---|
default | — | 文字 |
icon | { pressed: boolean } | 前置图标 |
pressed-icon | — | 按下时的前置图标 |
事件
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: boolean | 按下状态变化 |