backdrop
组件

Slider

一种允许用户在给定范围内选择数值的输入组件。

功能特性

  • 支持受控或非受控模式。
  • 支持多个滑块按钮。
  • 支持设置滑块按钮间的最小值。
  • 支持通过触摸或点击轨道来更新数值。
  • 支持从右到左(RTL)方向。
  • 完整的键盘导航支持。

安装

通过命令行安装该组件。

sh
$ npm add reka-ui

结构剖析

导入所有部件并进行组装。

vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
</script>

<template>
  <SliderRoot>
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
  </SliderRoot>
</template>

API 参考

Root

包含滑块的所有部件。在 form 中使用时,它会为每个滑块按钮渲染一个 input 元素,以确保事件能正确传播。

PropDefaultType
as
'span'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

defaultValue
[0]
number[]

The value of the slider when initially rendered. Use when you do not need to control the state of the slider.

dir
'ltr' | 'rtl'

The reading direction of the combobox when applicable.
If omitted, inherits globally from ConfigProvider or assumes LTR (left-to-right) reading mode.

disabled
false
boolean

When true, prevents the user from interacting with the slider.

inverted
false
boolean

Whether the slider is visually inverted.

max
100
number

The maximum value for the range.

min
0
number

The minimum value for the range.

minStepsBetweenThumbs
0
number

The minimum permitted steps between multiple thumbs.

modelValue
number[] | null

The controlled value of the slider. Can be bind as v-model.

name
string

The name of the field. Submitted with its owning form as part of a name/value pair.

orientation
'horizontal'
'vertical' | 'horizontal'

The orientation of the slider.

required
boolean

When true, indicates that the user must set the value before the owning form can be submitted.

step
1
number

The stepping interval.

thumbAlignment
'contain'
'contain' | 'overflow'

The alignment of the slider thumb.

  • contain: thumbs will be contained within the bounds of the track.
  • overflow: thumbs will not be bound by the track. No extra offset will be added.
EmitPayload
update:modelValue
[payload: number[]]

Event handler called when the slider value changes

valueCommit
[payload: number[]]

Event handler called when the value changes at the end of an interaction.

Useful when you only need to capture a final value e.g. to update a backend service.

Slots (default)Payload
modelValue
number[] | null

Current slider values

Data AttributeValue
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

Track

包含 SliderRange 的轨道。

PropDefaultType
as
'span'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Data AttributeValue
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

Range

范围部件。必须位于 SliderTrack 内部。

PropDefaultType
as
'span'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Data AttributeValue
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

Thumb

可拖动的滑块按钮。可以渲染多个滑块按钮。

PropDefaultType
as
'span'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Data AttributeValue
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

示例

垂直方向

使用 orientation 属性创建垂直滑块。

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
</script>

<template>
  <SliderRoot
    class="SliderRoot"
    :default-value="[50]"
    orientation="vertical"
  >
    <SliderTrack class="SliderTrack">
      <SliderRange class="SliderRange" />
    </SliderTrack>
    <SliderThumb class="SliderThumb" />
  </SliderRoot>
</template>
css
/* styles.css */
.SliderRoot {
  position: relative;
  display: flex;
  align-items: center;
}
.SliderRoot[data-orientation="vertical"] {
  flex-direction: column;
  width: 20px;
  height: 100px;
}

.SliderTrack {
  position: relative;
  flex-grow: 1;
  background-color: grey;
}
.SliderTrack[data-orientation="vertical"] {
  width: 3px;
}

.SliderRange {
  position: absolute;
  background-color: black;
}
.SliderRange[data-orientation="vertical"] {
  width: 100%;
}

.SliderThumb {
  display: block;
  width: 20px;
  height: 20px;
  background-color: black;
}

创建范围滑块

添加多个滑块按钮和数值以创建范围滑块。

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
</script>

<template>
  <SliderRoot :default-value="[25, 75]">
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
    <SliderThumb />
  </SliderRoot>
</template>

定义步长

使用 step 属性来增加步进间隔。

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
</script>

<template>
  <SliderRoot
    :default-value="[50]"
    :step="10"
  >
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
  </SliderRoot>
</template>

防止滑块按钮重叠

使用 minStepsBetweenThumbs 来避免滑块按钮数值相同。

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
</script>

<template>
  <SliderRoot
    :default-value="[25, 75]"
    :step="10"
    :min-steps-between-thumbs="1"
  >
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
    <SliderThumb />
  </SliderRoot>
</template>

无障碍访问

遵循 Slider WAI-ARIA 设计模式

键盘交互

KeyDescription
ArrowRight
step 量增加数值。
ArrowLeft
step 量减少数值。
ArrowUp
step 量增加数值。
ArrowDown
step 量减少数值。
PageUp
按更大的 step 量增加数值。
PageDown
按更大的 step 量减少数值。
Shift + ArrowUp
按更大的 step 量增加数值。
Shift + ArrowDown
按更大的 step 量减少数值。
Home
将数值设置为最小值。
End
将数值设置为最大值。

反转滑块

当滑块被 (反转)时,部分控制操作也会根据 (方向)进行反转。

  • 当滑块为 (水平,默认)时,ArrowRightArrowLeftHomeEnd 会被反转。
  • 当滑块为 (垂直)时,ArrowUpArrowDownPageUpPageDownShift + ArrowUpShift + ArrowDown 会被反转。

自定义 API

通过将原始部件抽象到你自己的组件中来创建自定义 API。

抽象所有部件

此示例抽象了 Slider 的所有部件,使其可以作为自闭合元素使用。

用法

vue
<script setup lang="ts">
import { Slider } from './your-slider'
</script>

<template>
  <Slider :default-value="[25]" />
</template>

实现

ts
// your-slider.ts
export { default as Slider } from 'Slider.vue'
vue
 <!-- Slider.vue -->
<script setup lang="ts">
import type { SliderRootEmits, SliderRootProps } from 'reka-ui'
import { SliderRange, SliderRoot, SliderThumb, SliderTrack, useForwardPropsEmits } from 'reka-ui'

const props = defineProps<SliderRootProps>()
const emits = defineEmits<SliderRootEmits>()

const forward = useForwardPropsEmits(props, emits)
</script>

<template>
  <SliderRoot v-slot="{ modelValue }" v-bind="forward">
    <SliderTrack>
      <SliderRange />
    </SliderTrack>

    <SliderThumb
      v-for="(_, i) in modelValue"
      :key="i"
    />
  </SliderRoot>
</template>

注意事项

鼠标事件不会被触发

由于我们在实现过程中遇到的一个限制,以下示例无法按预期工作,@mousedown@mousedown 事件处理器不会被触发:

vue
<SliderRoot
  @mousedown="() => { console.log('onMouseDown')  }"
  @mouseup="() => { console.log('onMouseUp')  }"
>

</SliderRoot>

我们建议改用指针事件(例如 @pointerdown@pointerup)。无论存在上述何种限制,这些事件都更适合跨平台/设备处理,因为它们适用于所有指针输入类型(鼠标、触摸、笔等)。