Slider 滑块
在一段连续范围里拖动选值:音量、透明度这类单个值,或价格、日期这类区间。
单值与范围
value 是数组,滑块数等于它的长度:一个值一个滑块,两个值就是范围(HTML 里写成逗号分隔)。没有可见标签时写 aria-label。
<pt-slider value="50" aria-label="音量"></pt-slider>
<pt-slider value="20,80" aria-label="价格区间"></pt-slider>取值范围、步长与间隔
min / max / step 决定可取的值,外部给的值按它们夹紧、对齐。min-steps-between-thumbs 让两个滑块至少隔开几步。
<pt-slider value="200,600" min="0" max="1000" step="50" min-steps-between-thumbs="2" aria-label="预算"></pt-slider>竖向与禁用
orientation="vertical" 时下端是最小值,改宿主的 height 调长度。禁用只淡化已填充的一段、指针变成禁止符号,滑块本身不变。
<pt-slider orientation="vertical" value="60" style="height: 120px" aria-label="竖向"></pt-slider>
<pt-slider orientation="vertical" value="30,70" style="height: 120px" aria-label="竖向范围"></pt-slider>
<pt-slider value="40" disabled aria-label="禁用"></pt-slider>取值
value 是数字数组,单值也写成数组([50]),滑块数等于数组长度。HTML 里写成逗号分隔的字符串:
html
<!-- 一个滑块 -->
<pt-slider value="50" aria-label="音量"></pt-slider>
<!-- 范围:两个滑块 -->
<pt-slider value="20,80" aria-label="价格区间"></pt-slider>- 缺省、
null、空串、空数组都按[min]处理(一个滑块停在最小值)—— Angular 的ngModel初值null、Vue 的v-model初值undefined都能直接用。 - 外部给的值渲染前按
min/max夹紧、按step(从min起算)对齐、从小到大排序。这份规整只用于显示、读屏和表单提交,不回写value:使用方赋的值原样保留,直到用户拖动或按键时组件写回一个规整过的新数组并发ptChange。 max不在步长网格上时(max=10 step=3),最大只能取到不超过它的最后一格(9)。
事件
| 事件 | 何时触发 |
|---|---|
ptChange | 值每变化一次(拖动中持续触发)。v-model / ngModel 绑它 |
ptCommit | 一次操作结束且值变了:指针松开,或每一次改变了值的按键 |
两者的 detail 都是新的数组,都只在用户交互时触发,外部改 value 不发。只在「定下来」时才请求接口的场景监听 ptCommit:
html
<pt-slider value="50" aria-label="音量"></pt-slider>
<script>
document.querySelector('pt-slider').addEventListener('ptCommit', event => {
saveVolume(event.detail[0]);
});
</script>交互
- 指针:拖动滑块;点轨道时最近的滑块跳过去,按住不放继续拖。触屏上按住拖动不会滚动页面。
- 键盘:← ↓ 减一步、→ ↑ 加一步(横向 RTL 下左右对调),PageDown / PageUp 与 Shift + 方向键十步,Home / End 到两端。
- 多个滑块互不交叉;
min-steps-between-thumbs让相邻两个至少隔开几步(默认 0,可以重叠)。两个滑块重叠时按住拖,往哪边拖就拖动哪一个。 - 竖向(
orientation="vertical")下端是最小值,宿主默认 16px 宽、160px 高,改宿主的height即可。
禁用
禁用时已填充的一段淡到 30%、指针变成禁止符号,滑块不可聚焦、不响应任何操作。滑块本身完全不变: 给白色实心的滑块压透明度,深色轨道会从它身体里透出来;换成更淡的描边又会糊进轨道里、看不出滑到了哪儿。
表单
放在 <form> 里按 name 提交,每个滑块一条,同一个名字提交多次:
js
new FormData(form).getAll('price'); // ['20', '80']表单重置回到初始值;外层 <fieldset disabled> 会禁用它。
无障碍
每个滑块是 role="slider",带 aria-valuenow / aria-valuemin / aria-valuemax / aria-orientation。
- 一个滑块:
aria-label(包装层里是ariaLabelText)就是它的名字;用<pt-label for>关联时标签文字优先。 - 多个滑块:宿主是
role="group",aria-label(或关联的pt-label)是整组的名字;各滑块默认念「最小值 / 最大值」(三个及以上按序号), 要换说法用thumbLabels(只能 JS 赋值)。 - 读屏默认念数字,要带单位就给
formatValue(只能 JS 赋值),它的返回值写进aria-valuetext:
js
slider.formatValue = value => `${value} 元`;定制
通过 ::part() 调整:base、track(轨道)、range(已填充的一段)、thumb(每个滑块)。
API
属性
| 属性 | Attribute | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
ariaLabelText | aria-label | string | undefined | — | 无障碍名称:原生 HTML 里写 aria-label,React / Vue / Angular 包装层里属性名是 ariaLabelText。 一个滑块时它就是滑块的名字;多个滑块时是整组的名字(各滑块另见 `thumbLabels`)。页面上没有可见标签时必须给。 |
disabled | disabled | boolean | false | 禁用:不响应指针与键盘、滑块不可聚焦。只反映使用方自己写的值:外层原生 `<fieldset disabled>`、 pt-field / pt-field-set 的禁用另经继承通道生效,不改写它 |
formatValue | — | ((value: number, index: number) => string) | undefined | — | 把值格式化成读屏念的文字(`aria-valuetext`),如 `v => v + ' 元'`。只能用 JS 赋值。 缺省不写 aria-valuetext,读屏直接念数字 |
inheritedDisabled | inherited-disabled | boolean | false | 外层 pt-field / pt-field-set 下发的禁用。内部继承通道:由它们以 attribute 维护,不建议使用方直接写。 有效禁用是 `disabled` 与它的并集;父元素只写这一条、不碰 `disabled`,读 `el.disabled` 得到的始终是使用方自己写的值 |
max | max | number | 100 | 最大值,默认 100。小于 `min` 时按 `min` 处理 |
min | min | number | 0 | 最小值,默认 0 |
minStepsBetweenThumbs | min-steps-between-thumbs | number | 0 | 多个滑块时相邻两个之间至少相隔几步(乘以 `step`),默认 0:可以重叠,但不能交叉 |
name | name | string | undefined | — | 提交表单时的字段名。多个滑块时同一个名字提交多条 |
orientation | orientation | "horizontal" | "vertical" | 'horizontal' | 方向:horizontal 横向(默认);vertical 竖向,下端是最小值 |
step | step | number | 1 | 步长,默认 1,从 `min` 起算。`max` 不在步长网格上时,最大只能取到不超过它的最后一格 |
thumbLabels | — | string[] | undefined | — | 多个滑块时各自的读屏名字,按序号对应。只能用 JS 赋值。缺省时两个滑块念「最小值 / 最大值」, 三个及以上念「第 n 个值,共 m 个」(走 locale 注册表);只有一个滑块时不用它,名字取 `aria-label` |
value | value | number[] | string | [] | 当前值,一个滑块一个数:单值也写成数组(`[50]`),范围写两个(`[20, 80]`)。 数组只能用 JS / 框架绑定赋值;写成 HTML attribute 时用**逗号分隔**(`value="20,80"`,各段去掉首尾空白)。 缺省按 `[min]`。外部赋的值不回写(规整规则见组件说明);用户交互时组件写回一个新数组并发 `ptChange`。 |
事件
| 事件 | detail 类型 | 说明 |
|---|---|---|
ptChange | number[] | 值在用户交互中每变化一次就触发(拖动中持续触发),detail 是新的 `value`(规整过的数组)。 Vue 的 v-model 与 Angular 的 ngModel 绑在它上面。外部直接改 `value` 不触发。 冒泡(组件默认):滑块不会自我嵌套,冒泡不会串到别的绑定上。 |
ptCommit | number[] | 一次操作结束、且值与操作开始前不同时触发:指针松开,或每一次改变了值的按键。detail 同 `ptChange`。 适合只在「定下来」时才请求接口的场景 |
方法
| 方法 | 说明 |
|---|---|
setFocus(options?: FocusOptions) => Promise<void> | 聚焦第一个滑块 |
可定制的内部元素(::part())
| part | 说明 |
|---|---|
base | 承载轨道与滑块的容器 |
range | 已填充的一段(单个滑块时从起点到滑块,多个时在首末两个滑块之间) |
thumb | 每个滑块 |
track | 轨道 |