slider —— 滑桿
هذا المحتوى غير متوفر بلغتك بعد.
滑桿把數值選擇變成了空間操作:拖曳比輸入更直觀,且能一眼看到值在範圍內的位置。core/slider 管的是「值 ↔ 位置」的雙向換算、步進吸附、區間(range)模式的兩點初值,以及 APG slider 語義。
- 各端實作
LhSlider:音量、價格區間、透明度調節。 - 值域連續或步進粒度較粗的場景。
- 不該用它:精確數值輸入(用
input-number,滑桿無法表達「37」這類非步進值)。
import { snapToStep, clampAndSnap, getValueFromPosition, getPositionFromValue, getSliderClassNames, getInitialValue, buildMarksList, getSliderThumbAria,} from '@lh-ui/share/core/slider'import type { LhSliderState, LhSliderMark } from '@lh-ui/share/core/slider'snapToStep 在 step 非有限或 <= 0 時原值傳回,而不是傳回 NaN——step: 0 會讓取模運算產生 NaN,這裡把「非法步長」當作「不吸附」,把純邊界鉗制留給 clampAndSnap。職責分離:吸附與鉗制是兩件獨立的事。
getPositionFromValue 的 max === min 傳回 0 是避免除零:值域退化為點時,滑桿自然應當在起點。
getInitialValue 對區間模式傳回 [min 鉗制, (min+max)/2 鉗制]——第二個滑塊預設在中點而不是 max,這是視覺考量(兩個滑塊貼在一起看起來像 bug)。
| 函式 | 簽名 | 傳回 | 作用 |
|---|---|---|---|
snapToStep |
(value: number, min: number, step: number) => number |
吸附值 | 按 step 對齊最近格點 |
clampAndSnap |
(value: number, min: number, max: number, step: number) => number |
規整值 | 先吸附後鉗制 |
getValueFromPosition |
(pct: number, min: number, max: number, step: number) => number |
數值 | 百分比 → 值 |
getPositionFromValue |
(value: number, min: number, max: number) => number |
百分比 [0,1] | 值 → 位置 |
getSliderClassNames |
(state: LhSliderState) => string[] |
類別名 | disabled/range/size |
getInitialValue |
(state: LhSliderState) => number | [number, number] |
初值 | 區間傳回兩點 |
buildMarksList |
(marks?: Record<number, string>) => LhSliderMark[] |
刻度陣列 | 按 value 升序 |
getSliderThumbAria |
(options: { value, min, max, vertical?, disabled?, ariaValueText? }) => LhAriaAttrs |
aria 屬性包 | slider 語義 |
export interface LhSliderMark { label: string value: number}
export interface LhSliderState { value: number | [number, number] | null min: number max: number step: number disabled: boolean range: boolean // 區間模式(兩個滑塊) showInput: boolean // 配 input-number 聯動 size: LhComponentSize marks: Record<number, string> | undefined}getSliderThumbAria 輸出 APG slider 語義。區間模式必須對兩個滑塊各調一次:
getSliderThumbAria({ value: 30, min: 0, max: 100 })// { role: 'slider', 'aria-valuenow': 30, 'aria-valuemin': 0, 'aria-valuemax': 100 }
getSliderThumbAria({ value: 60, min: 0, max: 100, vertical: true, disabled: true })// { role: 'slider', 'aria-valuenow': 60, 'aria-valuemin': 0, 'aria-valuemax': 100,// 'aria-orientation': 'vertical', 'aria-disabled': true }vertical輸出aria-orientation: 'vertical'(水平是預設方向,不宣告)。ariaValueText輸出aria-valuetext——當數值需要語義化表達時用(如「30%」或「慢速」),優先於 valuenow 播報。- 鍵盤互動(UI 層):←/→ 或 ↓/↑ 按 step 增減,Home/End 跳到 min/max,PageUp/Down 大步進。
import { getValueFromPosition, getPositionFromValue, snapToStep } from '@lh-ui/share/core/slider'
getValueFromPosition(0.5, 0, 100, 1) // 50getValueFromPosition(0.333, 0, 100, 5) // 35(吸附到 5 的倍數)getPositionFromValue(30, 0, 100) // 0.3getPositionFromValue(150, 0, 100) // 1(鉗制)getPositionFromValue(50, 50, 50) // 0(max===min 避免除零)snapToStep(7, 0, 5) // 5snapToStep(8, 0, 5) // 10snapToStep(7, 0, 0) // 7(非法 step 不吸附)buildMarksList({ 0: '低', 100: '高' }) // [{ label: '低', value: 0 }, { label: '高', value: 100 }]<!-- Vue3 --><div :class="getSliderClassNames({ value, min, max, step, disabled, range, showInput, size, marks })"> <div class="lh-slider__track"> <div class="lh-slider__bar" :style="{ width: pct + '%' }" /> <div class="lh-slider__button-wrapper" :style="{ left: pct + '%' }" v-bind="getSliderThumbAria({ value, min, max, disabled })" @pointerdown="startDrag" > <div class="lh-slider__button" /> </div> <template v-if="marks"> <div v-for="mark in buildMarksList(marks)" :key="mark.value" class="lh-slider__marks"> <span class="lh-slider__mark" :style="{ left: getPositionFromValue(mark.value, min, max) * 100 + '%' }"> {{ mark.label }} </span> </div> </template> </div></div>// React:拖曳用 pointer events + getBoundingClientRect 算百分比// const pct = (clientX - rect.left) / rect.width// onChange(getValueFromPosition(pct, min, max, step))// uniapp:<slider> 是內置組件(單滑塊),支援 min/max/step/show-value;// 區間模式與 marks 需自訂 view 實作,拖曳用 @touchmove| 類別名 | 語義 |
|---|---|
.lh-slider |
基礎類 |
.lh-slider--{small|large} |
尺寸檔(滑塊大小) |
.lh-slider--disabled |
停用 |
.lh-slider--range |
區間模式(兩個滑塊 + 中間高亮段) |
.lh-slider__track |
軌道 |
.lh-slider__bar |
已選區間(高亮段) |
.lh-slider__button-wrapper / __button |
滑塊 |
.lh-slider__marks / __mark |
刻度 |
.lh-slider__input / __input-text |
連動輸入框 |
軌道色 --lh-fill-color,已選段 --lh-primary-color。
getPositionFromValue傳回 [0,1] 的小數,UI 層拼%;別誤以為傳回百分比。- 吸附與刻度的對齊:
marks的 value 應當是 step 的倍數,否則刻度點會落在兩個吸附值之間,使用者拖不到那裡。 - 區間模式的交叉:兩個滑塊可以互相穿過(UI 層通常禁止,或自動交換),core 的
clampAndSnap不處理這個語義。 - 垂直模式:
vertical時軌道高度代替寬度,換算的分母要改;core 的getValueFromPosition是軸無關的(吃百分比),UI 層負責算 pct。 showInput的連動:input-number的 min/max/step 應與 slider 一致,否則兩者值域不一致。
@lh-ui/share/core/slider → getValueFromPosition( )返回值
(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue