Slider
功能特性
- 支持受控或非受控模式。
- 支持多个滑块按钮。
- 支持设置滑块按钮间的最小值。
- 支持通过触摸或点击轨道来更新数值。
- 支持从右到左(RTL)方向。
- 完整的键盘导航支持。
安装
通过命令行安装该组件。
$ npm add reka-ui结构剖析
导入所有部件并进行组装。
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
</script>
<template>
<SliderRoot>
<SliderTrack>
<SliderRange />
</SliderTrack>
<SliderThumb />
</SliderRoot>
</template>API 参考
Root
包含滑块的所有部件。在 form 中使用时,它会为每个滑块按钮渲染一个 input 元素,以确保事件能正确传播。
| Prop | Default | Type |
|---|---|---|
as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange 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. | |
disabled | false | booleanWhen |
inverted | false | booleanWhether the slider is visually inverted. |
max | 100 | numberThe maximum value for the range. |
min | 0 | numberThe minimum value for the range. |
minStepsBetweenThumbs | 0 | numberThe minimum permitted steps between multiple thumbs. |
modelValue | number[] | nullThe controlled value of the slider. Can be bind as | |
name | stringThe 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 | booleanWhen | |
step | 1 | numberThe stepping interval. |
thumbAlignment | 'contain' | 'contain' | 'overflow'The alignment of the slider thumb.
|
| Emit | Payload |
|---|---|
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[] | nullCurrent slider values |
| Data Attribute | Value |
|---|---|
[data-disabled] | 禁用时存在 |
[data-orientation] | "vertical" | "horizontal" |
Track
包含 SliderRange 的轨道。
| Prop | Default | Type |
|---|---|---|
as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Data Attribute | Value |
|---|---|
[data-disabled] | 禁用时存在 |
[data-orientation] | "vertical" | "horizontal" |
Range
范围部件。必须位于 SliderTrack 内部。
| Prop | Default | Type |
|---|---|---|
as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Data Attribute | Value |
|---|---|
[data-disabled] | 禁用时存在 |
[data-orientation] | "vertical" | "horizontal" |
Thumb
可拖动的滑块按钮。可以渲染多个滑块按钮。
| Prop | Default | Type |
|---|---|---|
as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Data Attribute | Value |
|---|---|
[data-disabled] | 禁用时存在 |
[data-orientation] | "vertical" | "horizontal" |
示例
垂直方向
使用 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;
}创建范围滑块
添加多个滑块按钮和数值以创建范围滑块。
// 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 属性来增加步进间隔。
// 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 来避免滑块按钮数值相同。
// 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>无障碍访问
键盘交互
| Key | Description |
|---|---|
ArrowRight | 按 step 量增加数值。 |
ArrowLeft | 按 step 量减少数值。 |
ArrowUp | 按 step 量增加数值。 |
ArrowDown | 按 step 量减少数值。 |
PageUp | 按更大的 step 量增加数值。 |
PageDown | 按更大的 step 量减少数值。 |
Shift + ArrowUp | 按更大的 step 量增加数值。 |
Shift + ArrowDown | 按更大的 step 量减少数值。 |
Home | 将数值设置为最小值。 |
End | 将数值设置为最大值。 |
反转滑块
当滑块被 (反转)时,部分控制操作也会根据 (方向)进行反转。
- 当滑块为 (水平,默认)时,ArrowRight、ArrowLeft、Home 和 End 会被反转。
- 当滑块为 (垂直)时,ArrowUp、ArrowDown、PageUp、PageDown、Shift + ArrowUp 和 Shift + ArrowDown 会被反转。
自定义 API
通过将原始部件抽象到你自己的组件中来创建自定义 API。
抽象所有部件
此示例抽象了 Slider 的所有部件,使其可以作为自闭合元素使用。
用法
<script setup lang="ts">
import { Slider } from './your-slider'
</script>
<template>
<Slider :default-value="[25]" />
</template>实现
// your-slider.ts
export { default as Slider } from 'Slider.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 事件处理器不会被触发:
<SliderRoot
@mousedown="() => { console.log('onMouseDown') }"
@mouseup="() => { console.log('onMouseUp') }"
>
…
</SliderRoot>我们建议改用指针事件(例如 @pointerdown、@pointerup)。无论存在上述何种限制,这些事件都更适合跨平台/设备处理,因为它们适用于所有指针输入类型(鼠标、触摸、笔等)。
