<script setup lang="ts">
import { ref } from 'vue'
import { Slider } from '@hina-ui/vue'
const volume = ref(60)
</script>
<template>
<Slider v-model="volume" aria-label="音量" class="w-64" />
</template>
vue
用法
import { Slider } from '@hina-ui/vue'
ts
滑块在 min 与 max 之间取一个数,v-model 绑定当前值。拖动过程中值持续更新,松手时另发一次 commit。未声明的属性都会传给拇指元素,应当用 aria-label 或者 aria-labelledby 命名。宽度归布局,滑块本身撑满容器。
当前值:40
<script setup lang="ts">
import { ref } from 'vue'
import { Slider, Stack, Text } from '@hina-ui/vue'
const brightness = ref(40)
</script>
<template>
<Stack gap="sm" class="w-64">
<Slider v-model="brightness" aria-label="亮度" />
<Text size="sm" tone="muted">当前值:{{ brightness }}</Text>
</Stack>
</template>
vue
示例
范围与步长
min、max 与 step 决定取值范围与粒度,键盘方向键也按 step 移动。
<script setup lang="ts">
import { ref } from 'vue'
import { Slider } from '@hina-ui/vue'
const rating = ref(3.5)
</script>
<template>
<Slider v-model="rating" :min="1" :max="5" :step="0.5" aria-label="评分" class="w-64" />
</template>
vue
方向
dir 支持 ltr 和 rtl,优先于 Reka 的全局方向配置;未配置时继承外层元素的 dir。切换方向会同步更新轨道、拇指、刻度点与刻度文字。
RTL 下最小值在右、最大值在左;右方向键减小数值,左方向键增大数值,Home / End 仍分别跳到最小值与最大值。
LTR
RTL
<script setup lang="ts">
import { ref } from 'vue'
import { Slider, Stack, Text } from '@hina-ui/vue'
const value = ref(25)
const marks = [0, 25, 50, 75, 100].map(value => ({ value, label: String(value) }))
</script>
<template>
<Stack gap="lg" class="w-72 max-w-full">
<Stack v-for="dir in ['ltr', 'rtl'] as const" :key="dir" gap="xs">
<Text size="sm" tone="muted">{{ dir.toUpperCase() }}</Text>
<Slider
v-model="value"
:dir="dir"
:marks="marks"
:step="5"
:aria-label="'数值 (' + dir.toUpperCase() + ')'"
/>
</Stack>
</Stack>
</template>
vue
刻度
marks 在轨道上放刻度点,带 label 的刻度在下方显示文字。
<script setup lang="ts">
import { ref } from 'vue'
import { Slider } from '@hina-ui/vue'
const speed = ref(50)
const marks = [
{ value: 0, label: '慢' },
{ value: 25 },
{ value: 50, label: '中' },
{ value: 75 },
{ value: 100, label: '快' },
]
</script>
<template>
<Slider v-model="speed" :step="25" :marks="marks" aria-label="翻页速度" class="w-64" />
</template>
vue
取值标签
取值标签是一个 Tooltip,以拇指为触发器,随拇指移动,接近视口边缘时会翻转到另一侧。默认在悬停、聚焦与拖动时显示当前值;label 为 always 时始终显示,为 none 时不显示。format 定制显示的文字,默认按当前语言格式化数字。与 IconButton 的提示相同,它依赖应用中的 TooltipProvider,缺少时不显示。
<script setup lang="ts">
import { ref } from 'vue'
import { Slider, Stack } from '@hina-ui/vue'
const quality = ref(80)
const opacity = ref(30)
</script>
<template>
<Stack gap="lg" class="w-64 pt-6">
<Slider
v-model="quality"
label="always"
:format="(v: number) => `${v}%`"
aria-label="图片质量"
/>
<Slider v-model="opacity" label="none" aria-label="遮罩透明度" />
</Stack>
</template>
vue
尺寸
size 有 sm、md、lg 三档,轨道高 20、24、28 像素,拇指 12、16、20 像素,与 Switch 相同。
<script setup lang="ts">
import { Slider, Stack } from '@hina-ui/vue'
</script>
<template>
<Stack gap="sm" class="w-64">
<Slider size="sm" :model-value="30" aria-label="小号" />
<Slider size="md" :model-value="50" aria-label="中号" />
<Slider size="lg" :model-value="70" aria-label="大号" />
</Stack>
</template>
vue
状态
disabled 禁用整个滑块。
<script setup lang="ts">
import { Slider } from '@hina-ui/vue'
</script>
<template>
<Slider disabled :model-value="45" aria-label="已禁用" class="w-64" />
</template>
vue
松手时提交
commit 只在一次拖动或者一次按键结束时触发,适合触发请求之类代价较高的操作。
拖动中:20,松手后:20
<script setup lang="ts">
import { ref } from 'vue'
import { Slider, Stack, Text } from '@hina-ui/vue'
const value = ref(20)
const committed = ref(20)
</script>
<template>
<Stack gap="sm" class="w-64">
<Slider v-model="value" aria-label="阈值" @commit="committed = $event" />
<Text size="sm" tone="muted">拖动中:{{ value }},松手后:{{ committed }}</Text>
</Stack>
</template>
vue
在表单中
放进 FormField 后,标签通过 aria-labelledby 关联到拇指,说明与错误信息由字段渲染;校验规则与提交交给 Form。
<script setup lang="ts">
import { reactive, ref } from 'vue'
import * as v from 'valibot'
import { Button, Form, FormField, Slider, Text } from '@hina-ui/vue'
const schema = v.object({
quality: v.pipe(v.number(), v.minValue(60, '画质不能低于 60')),
})
const values = reactive({ quality: 40 })
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="quality" label="导出画质" description="60 以下的画质会明显失真">
<Slider v-model="values.quality" :min="0" :max="100" :step="5" />
</FormField>
<Button type="submit" :loading="submitting" class="self-start">导出</Button>
<Text v-if="saved" tone="muted" size="sm">已导出:{{ saved }}</Text>
</Form>
</template>
vue
行为
- 点击轨道任意位置,拇指跳到该处并开始拖动;拖动时拇指与填充跟手,不带过渡;点击与键盘引起的跳动带过渡。
- 键盘 Tab 落在拇指上,左右方向键按
step移动,PageUp / PageDown 大步移动,Home / End 跳到两端。 - 悬停整条滑块时拇指落墨、取值标签淡入;按住拖动时加深。
无障碍
- 拇指是
role="slider",带aria-valuenow、aria-valuemin、aria-valuemax与aria-orientation。 - 通过
aria-label或者aria-labelledby给拇指命名;刻度对屏幕阅读器隐藏,屏幕阅读器读取的是aria-valuenow;取值标签显示时作为拇指的aria-describedby。
API
Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | number | — | 当前值,未绑定时落在 min |
min | number | 0 | 最小值 |
max | number | 100 | 最大值 |
step | number | 1 | 步长 |
dir | 'ltr' | 'rtl' | — | 方向,未指定时继承 |
marks | Array<{ value: number; label?: string }> | — | 刻度 |
label | 'auto' | 'always' | 'none' | 'auto' | 取值标签的显示方式 |
format | (value: number) => string | — | 取值标签的文字,默认按语言格式化 |
size | 'sm' | 'md' | 'lg' | 'md' | 尺寸 |
disabled | boolean | false | 是否禁用 |
class | string | — | 追加至根元素的类名 |
事件
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: number | 值变化时,拖动中持续触发 |
commit | value: number | 一次拖动或者按键结束时 |