Slider 滑块

在数值范围内拖动取值。

<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。

60 以下的画质会明显失真

<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
一次拖动或者按键结束时