Lzh on GitHub

Slider

用户从给定范围内选择值的输入。
<script setup lang="ts">
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
import { ref } from 'vue'

const sliderValue = ref([50])
</script>

<template>
  <SliderRoot
    v-model="sliderValue"
    class="relative flex items-center select-none touch-none w-[200px] h-5"
    :max="100"
    :step="1"
  >
    <SliderTrack class="bg-stone-500/30 relative grow rounded-full h-2">
      <SliderRange class="absolute bg-green-500 rounded-full h-full" />
    </SliderTrack>
    <SliderThumb
      class="block w-6 h-6 bg-white rounded-full hover:bg-stone-50 shadow-sm focus:outline-none focus:shadow-[0_0_0_2px] focus:shadow-grass9"
      aria-label="Volume"
    />
  </SliderRoot>
</template>

特性 (Features)

  • 可控或非控。
  • 支持多个滑块。
  • 支持滑块之间的最小值。
  • 支持触摸或点击轨道更新值。
  • 支持从右到左 (RTL) 方向。
  • 完整的键盘导航。

安装 (Installation)

从命令行安装组件。

$ npm add reka-ui

结构 (Anatomy)

导入所有部件并组装它们。

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

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

API 参考 (API Reference)

根 (Root)

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

属性默认值类型描述
as'span'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。
defaultValue[0]number[]滑块初始渲染时的值。当您不需要控制滑块状态时使用。
dir'ltr' | 'rtl'组合框的阅读方向(如果适用)。如果省略,则全局继承自 ConfigProvider 或假定为 LTR(从左到右)阅读模式。
disabledfalsebooleantrue 时,阻止用户与滑块交互。
invertedfalseboolean滑块是否视觉反转。
max100number范围的最大值。
min0number范围的最小值。
minStepsBetweenThumbs0number多个滑块之间允许的最小步长。
modelValuenumber[] | null滑块的受控值。可以通过 v-model 绑定。
namestring字段的名称。作为名称/值对的一部分随其所属的表单一起提交。
orientation'horizontal''vertical' | 'horizontal'滑块的方向。
requiredbooleantrue 时,表示用户必须在提交所属表单之前设置值。
step1number步进间隔。
thumbAlignment'contain''contain' | 'overflow'滑块的对齐方式。contain: 滑块将包含在轨道边界内。overflow: 滑块不受轨道限制。不会添加额外偏移。

发送事件

事件名称Payload描述
update:modelValue[payload: number[]]滑块值更改时调用的事件处理程序。
valueCommit[payload: number[]]交互结束时值更改时调用的事件处理程序。当您只需要捕获最终值(例如更新后端服务)时很有用。

默认插槽

插槽参数插槽参数类型描述
modelValuenumber[] | null当前滑块值

数据属性 (Data Attributes)

数据属性
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

轨道 (Track)

包含 SliderRange 的轨道。

属性默认值类型描述
as'span'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

数据属性 (Data Attributes)

数据属性
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

范围 (Range)

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

属性默认值类型描述
as'span'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

数据属性 (Data Attributes)

数据属性
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

滑块 (Thumb)

一个可拖动的滑块。您可以渲染多个滑块。

属性默认值类型描述
as'span'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

数据属性 (Data Attributes)

数据属性
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

示例 (Examples)

垂直方向 (Vertical orientation)

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

// 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>
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;
}

创建范围 (Create a range)

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

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

定义步长 (Define step size)

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

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>

防止滑块重叠 (Prevent thumb overlap)

使用 minStepsBetweenThumbs 避免滑块具有相同的值。

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

可访问性 (Accessibility)

遵循 滑块 WAI-ARIA 设计模式

键盘交互 (Keyboard Interactions)

按键描述
ArrowRightstep 量增加值。
ArrowLeftstep 量减少值。
ArrowUpstep 量增加值。
ArrowDownstep 量减少值。
PageUp以更大的 step 增加值。
PageDown以更大的 step 减少值。
Shift + ArrowUp以更大的 step 增加值。
Shift + ArrowDown以更大的 step 减少值。
Home将值设置为最小值。
End将值设置为最大值。

反转滑块 (Inverted sliders)

当滑块被 inverted 时,一些控件也会反转,具体取决于 orientation

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

自定义 API (Custom APIs)

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

抽象所有部分 (Abstract all parts)

此示例抽象了所有 Slider 部分,因此它可以作为自闭合元素使用。

用法 (Usage)

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

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

实现 (Implementation)

your-slider.ts
export { default as Slider } from './Slider.vue'
Slider.vue
<script setup lang="ts">
import type { SliderRootEmits, SliderRootProps } from 'reka-ui'
import { SliderRoot, SliderRange, 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>

注意事项 (Caveats)

不触发鼠标事件 (Mouse events are not fired)

由于我们实现过程中遇到的限制,以下示例不会按预期工作,并且 @mousedown@mouseup 事件处理程序不会被触发:

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

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