生态产品多个设计器现已发布正式版

查看生态总览
跳转到内容

Slider 滑块 ​

在连续或离散的区间内拖出一个值或一段范围。

用法 ​

值恒为数组,单滑块即长度 1;方向键移动一格 step,PageUp 与 PageDown 按 largeStep,Home 与 End 到达端点

组件结构 ​

加粗的是必需部件。

data-scope="slider":root · label · control · track · range · thumb · value-text · tick-group · tick · tick-label · hidden-input

示例 ​

区间选择 ​

两个拇指互为对方的边界、永不交叉,minStepsBetweenThumbs 再为它们之间留出格数;getValueText 把值转换为读屏可朗读的文本

竖向 ​

orientation 换为 vertical 后整条控件收为一块,键盘与拖动的方向随之翻转

禁用与只读 ​

禁用的拇指退出 Tab 序列、值也不再随表单提交;只读仍可聚焦与朗读,只是不可推动

颜色 ​

tone 决定已填轨道与滑块使用哪族颜色,不写时沿用品牌色

尺寸 ​

size 改变轨道厚度与滑块直径,不写即默认中档

文字方向 ​

dir 换为 rtl 后轨道从右向左填充,左右两键的语义随之对调;上下键与 Home、End 不受影响

滑块中的内容 ​

thumb 是一个普通容器,放置什么由作者决定;容纳空间依靠 --xh-slider-thumb-size 撑开直径

45%

轨道刻度 ​

刻度分圆点与文案两层:圆点固定在轨道上、文案排在下方且点击跳转到该值,落入已选区间的刻度分段上色;snapToMarks 使拖动/点击/键盘只落在刻度上

0°C26°C37°C沸腾
0°C26°C37°C沸腾

拖动时的值气泡 ​

value-text 挂在 thumb 中即随之移动;推动时由皮肤显示它,气泡中的文字取自作者的格式化函数

已选:¥1,800

离散档位 ​

可选值不必是等距数值:让滑块在档位下标上移动,宿主再把下标映射回自己的取值表,键盘与拖动都只落在档位上

可选:1 / 5 / 10 / 50 / 100 / 500

反向 ​

inverted 把 min 放到轨道末端,已选区间从末端画起;竖排时 0 米在上、越往下越深,方向键跟随屏幕方向

整段拖动 ​

draggableRange 让两端拇指之间的轨道可以整段拖动,时间窗宽度不变地平移;按在拇指上仍只推那一个

不填充轨道 ​

取值没有「多少」之分时关掉 trackFill,只留底槽与拇指,免得从一端画起的区间暗示大小

设计指引 ​

何时使用 ​

  • 用户关心的是相对位置而不是精确数字(音量、透明度、价格区间)。
  • 需要即时看到调整的效果。

何时不用 ​

特性 ​

  • 单值与区间共用一套结构,区间时 minStepsBetweenThumbs 防止两头交叉。
  • 轨道 2px、中性淡底,已选区间品牌色;拇指 12px 白底圆配 2px 品牌描边,不投影,悬停与拖动都不放大,聚焦与拖动画同一道环,收在描边以内;刻度点 8px 白底圆配 2px 描边(走过的取品牌色)。禁用时轨道、区间与拇指描边都退到中性淡底,拇指留白面。粗指针下控件沿交叉轴外扩到 44px 接住落指:外扩量按拇指直径补足,朝标签一侧不越过标签与控件之间的间距,点在标签上不会跳值。
  • marks 绘制刻度,snapToMarks 让值吸附到刻度。
  • 两个回调:拖动途中连续发出,松手时发出一次;持久化使用后者。
  • getValueText 决定读屏读出的内容,不只读数字。
  • inverted 把 min 放到轨道末端(横排在行尾、竖排在顶端),已选区间从末端画起;方向键跟随屏幕方向,拇指在屏幕上往哪边挪就按哪个键。插槽里的 thumbs[i].percent 与 range 仍按值的位置报,自绘内容反向时自己取 1 - percent。
  • draggableRange:多拇指时按住两端拇指之间的轨道拖动,整段区间一起平移、宽度不变,挪到头就停;按在拇指上仍只推那一个,按在区间外照旧抓最近的拇指。只认刻度落点(snapToMarks)时不生效。键盘仍按拇指逐个调整。
  • trackFill 关掉后不画已选区间、刻度也不按区间上色,只留底槽与拇指:取值没有「多少」之分(声道平衡、色温中点)时用它,免得从一端画起的区间暗示大小。
  • 不写结构时按标准结构铺出整套部件(Vue 不写默认插槽、React 不给 children、Web Components 不写部件或只写 root),三端出自同一个结构函数:label 给标题文字,控制区里依次是轨道与已选区间、刻度(给了 marks 才铺)、每个值一个拇指(给了 name 再带表单影子)。拖动时的值气泡不在其中,要用时手写结构。Web Components 里标题可以写在宿主的直接子节点 slot="label" 上接管。

组合 ​

最佳实践 ​

  • 两端标出最小与最大值,用户才能知道当前位置。
  • 拖动时用值气泡显示当前值,松手后收起。

反模式 ​

  • 区间很大却不提供数字输入,拖到精确值几乎不可能。
  • 在移动端把滑块做得过细过短。

API 参考 ​

产物 ​

层值
自定义元素<xh-slider>
Vue 组件XhSliderControl XhSliderHiddenInput XhSliderLabel XhSliderRange XhSliderRoot XhSliderThumb XhSliderTickGroup XhSliderTrack XhSliderValueText
组合式函数useSlider
状态机sliderMachine
皮肤@xihan-ui/styles/slider.css

Props ​

属性类型必填说明
labelledboolean作者渲染了 label 部件时置真,由适配器统计而不是判断标题文字是否有值。 为假时可聚焦部件不把 label 的 id 写进 aria-labelledby:指向未渲染的 id 是无效引用,作者写在控件上的 aria-label 也会被它压住。
ariaLabelstring不显示出来的名字,写成 aria-label 落在与字段标签同一个部件上。 放进字段(字段接线)或渲染了 label 部件时名字以它们为准,aria-labelledby 盖过它。
valuenumber[]
defaultValuenumber[]
minnumber
maxnumber
stepnumber
largeStepnumberPageUp / PageDown 的步长,默认 10 倍 step。
orientationOrientation
dirDirection
disabledboolean
readOnlyboolean
invalidboolean
requiredboolean必填:根与标题带 data-required(标题据此画星号)。拇指是 role=slider,不收 aria-required; 滑块恒有值,表单影子不带原生 required。
toneTone语气:brand / neutral / success / warning / danger / info,决定使用哪族颜色
sizeSize尺寸:sm / md / lg,决定拇指直径与轨道厚度
namestring表单字段名;多滑块时逐个 append。
minStepsBetweenThumbsnumber相邻滑块至少相隔的格数,默认 0(可以贴在一起但不能交换顺序)。
marksSliderMark[]刻度表:轨道上的圆点与文案,点击文案即跳到该值。
snapToMarksboolean只接受刻度落点:拖动、点击与键盘都吸附到最近 / 下一档刻度。
invertedboolean反向:min 落在轨道的末端(横排在行尾、竖排在顶端),已选区间从末端画起。 方向键跟随屏幕方向:拇指在屏幕上往哪边挪,按的就是哪个键。默认 false。
draggableRangeboolean多拇指时按住两端拇指之间的轨道拖动,整段区间一起平移、宽度不变;按在拇指上仍只推那一个。 只认刻度落点(snapToMarks)时不生效:整段平移会把拇指推离刻度。默认 false。
trackFillboolean画出已选区间(range 部件)并给落进区间的刻度上色,默认 true;关掉后轨道只剩底槽与拇指。
getValueText(details: SliderValueTextDetails) => string把值转换为可读文字,产出写入拇指的 aria-valuetext。 未提供时不写该属性,读屏回退为朗读 aria-valuenow。
onValueChange(details: SliderValueChangeDetails) => void每次推动都发出;拖动过程中连续发出。
onValueChangeEnd(details: SliderValueChangeEndDetails) => void只在一次操作结束时发出一次,适合用于发起请求。

SliderMark ​

marks 的元素。

字段类型必填说明
valuenumber是
labelstring

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changeSliderValueTextDetails值变化(拖动途中连续发出);detail 为 { value: number[] }
value-change-endSliderValueChangeEndDetails一次操作收尾时发出一次;detail 为 { value: number[], index: number }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhSliderRootdefaultSliderRootSlotProps
XhSliderRootlabel—
XhSliderTickGrouptickSliderTickGroupTickSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhSliderRootlabelReactNode标题。不给 children 时铺 label 部件。
XhSliderRootchildrenSlotChildren<SliderRootSlotProps>
XhSliderThumbindexnumber | string第几个滑块,多滑块时必须逐个写明;兼收字符串。
XhSliderTickGrouptickSlotChildren<SliderTickSlotProps>逐档刻度的文案接管口;未提供时填入刻度自带的 label。

状态 ​

以下名称仅用于内部状态机。

状态:idle · dragging

事件:VALUE.SET · THUMB.STEP · THUMB.TO_MIN · THUMB.TO_MAX · THUMB.SET · THUMB.FOCUS · DRAG.START · DRAG.MOVE · DRAG.END · FORM.RESET

判据:canDrag

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
valuenumber[]
range{ start: number, end: number }已选区间在轨道上的起止,0-1。
thumbsSliderThumbState[]
marksSliderMarkMeta[]刻度呈现数据:夹进区间、升序去重,带位置与分段上色标记。
draggingboolean
disabledboolean
readOnlyboolean
valueText(index: number) => string某个拇指的值文本:提供 getValueText 时是其产出,否则是值本身。
setValue(next: number[]) => void
setThumbValue(index: number, next: number) => void
getRootProps() => T['element']
getLabelProps() => T['label']
getControlProps() => T['element']
getTrackProps() => T['element']
getRangeProps() => T['element']
getThumbProps(index: number) => T['element']
getValueTextProps(index: number) => T['element']值气泡:挂在拇指中显示该拇指的当前值;aria-hidden,读屏使用拇指自身的 aria-valuetext。
getTickGroupProps() => T['element']刻度容器。
getTickProps(props: SliderTickProps) => T['element']刻度点:轨道上的圆点,纯装饰。
getTickLabelProps(props: SliderTickProps) => T['element']刻度文案:点击把最近的滑块跳到该档。
getHiddenInputProps(index: number) => T['input']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
ArrowRight / ArrowUpfocus in thumb, not disabled/readOnly按 step 增大;方向跟随屏幕:RTL 对调左右两键,inverted 再对调一次(竖直轨道 inverted 时 ArrowUp 朝 min)
ArrowLeft / ArrowDownfocus in thumb, not disabled/readOnly按 step 减小,同上对调规则
PageUpfocus in thumb, not disabled/readOnly按 largeStep 增大(默认 10 倍 step)
PageDownfocus in thumb, not disabled/readOnly按 largeStep 减小
Homefocus in thumb, not disabled/readOnly取 min;多滑块时取自己被邻居允许的下界
Endfocus in thumb, not disabled/readOnly取 max;多滑块时取自己被邻居允许的上界

ARIA ​

以下属性由 connect 生成。

部件属性值
thumbaria-disabled'true' | 'false'
thumbaria-labelprops.ariaLabel
thumbaria-labelledbylabel 部件的 id | undefined
thumbaria-orientationprops.orientation
thumbaria-valuemaxString(thumb.max)
thumbaria-valueminString(thumb.min)
thumbaria-valuenowString(thumb.value)
thumbaria-valuetextprop('getValueText')?.({ value: thumb.value, index: t…
thumbrole'slider'
value-textaria-hidden'true'
tickaria-hidden'true'

样式参考 ​

皮肤 ​

@xihan-ui/styles/slider.css 按 [data-scope="slider"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-slider 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-dragging''(条件成立时才出现)
rootdata-following''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-orientationprops.orientation
rootdata-readonly''(条件成立时才出现)
rootdata-required''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-toneprops.tone
labeldata-disabled''(条件成立时才出现)
labeldata-dragging''(条件成立时才出现)
labeldata-following''(条件成立时才出现)
labeldata-invalid''(条件成立时才出现)
labeldata-orientationprops.orientation
labeldata-readonly''(条件成立时才出现)
labeldata-required''(条件成立时才出现)
controldata-disabled''(条件成立时才出现)
controldata-dragging''(条件成立时才出现)
controldata-following''(条件成立时才出现)
controldata-invalid''(条件成立时才出现)
controldata-orientationprops.orientation
controldata-readonly''(条件成立时才出现)
trackdata-disabled''(条件成立时才出现)
trackdata-dragging''(条件成立时才出现)
trackdata-following''(条件成立时才出现)
trackdata-invalid''(条件成立时才出现)
trackdata-orientationprops.orientation
trackdata-readonly''(条件成立时才出现)
rangedata-disabled''(条件成立时才出现)
rangedata-draggable''(条件成立时才出现)
rangedata-dragging''(条件成立时才出现)
rangedata-following''(条件成立时才出现)
rangedata-invalid''(条件成立时才出现)
rangedata-orientationprops.orientation
rangedata-readonly''(条件成立时才出现)
thumbdata-disabled''(条件成立时才出现)
thumbdata-dragging''(条件成立时才出现)
thumbdata-following''(条件成立时才出现)
thumbdata-indexString(thumb.index)
thumbdata-invalid''(条件成立时才出现)
thumbdata-orientationprops.orientation
thumbdata-readonly''(条件成立时才出现)
value-textdata-disabled''(条件成立时才出现)
value-textdata-dragging''(条件成立时才出现)
value-textdata-following''(条件成立时才出现)
value-textdata-indexString(thumb.index)
value-textdata-invalid''(条件成立时才出现)
value-textdata-orientationprops.orientation
value-textdata-readonly''(条件成立时才出现)
tick-groupdata-disabled''(条件成立时才出现)
tick-groupdata-dragging''(条件成立时才出现)
tick-groupdata-following''(条件成立时才出现)
tick-groupdata-invalid''(条件成立时才出现)
tick-groupdata-orientationprops.orientation
tick-groupdata-readonly''(条件成立时才出现)
tickdata-passed''(条件成立时才出现)
tick-labeldata-passed''(条件成立时才出现)
hidden-inputdata-indexString(thumb.index)

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-slider-control-guttercontrol
root
margin-inlinehas([data-part='tick-label'])
orientation=horizontal
--xh-space-6slider 的 control、root 部件 margin-inline 覆盖槽。
--xh-slider-gaplabel
root
gap
margin-block-end
default--xh-space-1slider 的 label、root 部件 gap、margin-block-end 覆盖槽。
--xh-slider-label-fglabelcolordefault--xh-fg-mutedslider 的 label 部件 color 覆盖槽。
--xh-slider-label-fg-disabledlabelcolordisabled--xh-fg-mutedslider 的 label 部件 color 覆盖槽。
--xh-slider-label-font-sizelabelfont-sizedefault--xh-text-label-sizeslider 的 label 部件 font-size 覆盖槽。
--xh-slider-label-font-weightlabelfont-weightdefault--xh-text-label-weightslider 的 label 部件 font-weight 覆盖槽。
--xh-slider-label-gapcontrol
label
inset-block-end
inset-block-start
margin-block-end
@media (pointer: coarse)
default
orientation=horizontal
--xh-space-2slider 的 control、label 部件 inset-block-end、inset-block-start、margin-block-end 覆盖槽。
--xh-slider-range-bgrangebackgrounddefault--xh-_toneslider 的 range 部件 background 覆盖槽。
--xh-slider-range-bg-disabledrangebackgrounddisabled--xh-bg-subtle-hover-opaqueslider 的 range 部件 background 覆盖槽。
--xh-slider-range-bg-invalidrangebackgroundinvalid--xh-border-invalidslider 的 range 部件 background 覆盖槽。
--xh-slider-range-radiusrangeborder-radiusdefault--xh-shape-pillslider 的 range 部件 border-radius 覆盖槽。
--xh-slider-thumb-bgthumbbackgrounddefault--xh-bg-surfaceslider 的 thumb 部件 background 覆盖槽。
--xh-slider-thumb-bg-disabledthumbbackgrounddisabled--xh-bg-surfaceslider 的 thumb 部件 background 覆盖槽。
--xh-slider-thumb-borderthumbborderdefault--xh-_toneslider 的 thumb 部件 border 覆盖槽。
--xh-slider-thumb-border-disabledthumbborder-colordisabled--xh-bg-subtle-hover-opaqueslider 的 thumb 部件 border-color 覆盖槽。
--xh-slider-thumb-border-invalidthumbborder-colorinvalid--xh-border-invalidslider 的 thumb 部件 border-color 覆盖槽。
--xh-slider-thumb-radiusthumbborder-radiusdefault--xh-shape-circleslider 的 thumb 部件 border-radius 覆盖槽。
--xh-slider-thumb-sizecontrol
root
thumb
block-size
inline-size
inset-block-end
inset-block-start
inset-inline
margin-block-end
margin-block-start
margin-inline-start
@media (pointer: coarse)
default
orientation=horizontal
orientation=vertical
size=lg
size=sm
--xh-track-thumb-size-lg
--xh-track-thumb-size-md
--xh-track-thumb-size-sm
slider 的 control、root、thumb 部件 block-size、inline-size、inset-block-end、inset-block-start、inset-inline、margin-block-end、margin-block-start、margin-inline-start 覆盖槽。
--xh-slider-tick-bgtickbackgrounddefault--xh-bg-surfaceslider 的 tick 部件 background 覆盖槽。
--xh-slider-tick-bordertickborderdefault--xh-bg-subtle-hoverslider 的 tick 部件 border 覆盖槽。
--xh-slider-tick-border-activetickborder-colorpassed--xh-_toneslider 的 tick 部件 border-color 覆盖槽。
--xh-slider-tick-border-active-disabledtick
tick-group
border-colordisabled
passed
--xh-bg-subtle-hover-opaqueslider 的 tick、tick-group 部件 border-color 覆盖槽。
--xh-slider-tick-border-disabledtick
tick-group
border-colordisabled--xh-bg-subtleslider 的 tick、tick-group 部件 border-color 覆盖槽。
--xh-slider-tick-label-fgtick-labelcolordefault--xh-fg-subtleslider 的 tick-label 部件 color 覆盖槽。
--xh-slider-tick-label-fg-activetick-labelcolorpassed--xh-fg-defaultslider 的 tick-label 部件 color 覆盖槽。
--xh-slider-tick-label-fg-disabledtick-group
tick-label
colordisabled--xh-fg-disabledslider 的 tick-group、tick-label 部件 color 覆盖槽。
--xh-slider-tick-label-font-sizetick-labelfont-sizedefault--xh-text-caption-sizeslider 的 tick-label 部件 font-size 覆盖槽。
--xh-slider-tick-label-gaproot
tick-label
margin-block-start
margin-inline-start
default
orientation=vertical
--xh-space-1slider 的 root、tick-label 部件 margin-block-start、margin-inline-start 覆盖槽。
--xh-slider-tick-radiustickborder-radiusdefault--xh-shape-circleslider 的 tick 部件 border-radius 覆盖槽。
--xh-slider-tick-sizetickblock-size
inline-size
default--xh-space-2slider 的 tick 部件 block-size、inline-size 覆盖槽。
--xh-slider-track-bgtrackbackgrounddefault--xh-bg-subtle-hoverslider 的 track 部件 background 覆盖槽。
--xh-slider-track-bg-disabledtrackbackgrounddisabled--xh-bg-subtleslider 的 track 部件 background 覆盖槽。
--xh-slider-track-radiustrackborder-radiusdefault--xh-shape-pillslider 的 track 部件 border-radius 覆盖槽。
--xh-slider-track-thicknessroot
track
block-size
inline-size
orientation=horizontal
orientation=vertical
size=lg
--xh-stroke-strong
--xh-stroke-thick
slider 的 root、track 部件 block-size、inline-size 覆盖槽。
--xh-slider-value-text-bgvalue-textbackgrounddefault--xh-_toneslider 的 value-text 部件 background 覆盖槽。
--xh-slider-value-text-fgvalue-textcolordefault--xh-_tone-onslider 的 value-text 部件 color 覆盖槽。
--xh-slider-value-text-font-sizevalue-textfont-sizedefault--xh-text-caption-sizeslider 的 value-text 部件 font-size 覆盖槽。
--xh-slider-value-text-offsetvalue-textmargin-block-end
margin-inline
default
orientation=vertical
--xh-space-2slider 的 value-text 部件 margin-block-end、margin-inline 覆盖槽。
--xh-slider-value-text-pxvalue-textpadding-inlinedefault--xh-space-2slider 的 value-text 部件 padding-inline 覆盖槽。
--xh-slider-value-text-pyvalue-textpadding-blockdefault--xh-space-0_5slider 的 value-text 部件 padding-block 覆盖槽。
--xh-slider-value-text-radiusvalue-textborder-radiusdefault--xh-shape-controlslider 的 value-text 部件 border-radius 覆盖槽。
--xh-slider-vertical-lengthcontrolblock-sizeorientation=vertical10remslider 的 control 部件 block-size 覆盖槽。

动效 ​

动效角色:状态 · 指示与换位(见动效规范)。

background-color · block-size · border-color · inline-size · inset-block-end · inset-inline-start · opacity 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

响应式 ​

皮肤另按输入能力分档:pointer: coarse:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;只认物理方向的量乘 --xh-direction-sign 换向,按就近的 dir 走。

Released under The MIT License