컴포넌트/필드 컴포넌트

Slider (슬라이더)

VanillaFront 2026. 9. 12. 20:12

Va.Slider — 드래그로 값을 조절하는 슬라이더

수치 범위 안에서 thumb(손잡이)를 드래그해서 값을 조절하는 컴포넌트. HTML 표준 <input type="range">를 감싸되, 진행 바 색상 커스텀, 숫자 입력창 병기, min/max 라벨 표시, thumb 위 값 표시 등을 옵션으로 제공합니다.

  • 클래스: Va.Slider  va_slider.js:28
  • short name: slider
  • 상속: Va.PureField (Input·Combobox와 형제)
  • 파일: va_slider.js (별도 파일 — import 필요)
  • isContainer: true


1. 시작하기 전 — 별도 파일 import

va.js나 va_component.js엔 포함 안 됨. 사용 전 반드시:

import Va from '../../lib/va.js';
import '../../lib/va_slider.js';       // ← 이 한 줄이 필수

Va.Slider, Va.DoubleSlider, Va.StarSlider 같은 슬라이더 계열이 이 파일에 함께 정의되어 있습니다.


2. 기본 사용

{
    tagName: 'slider',
    value: 50,
    min: 0,
    max: 100,
    step: 1,
    onChange: 'onVolumeChange'
}
  • 슬라이더 rail(줄) + thumb(손잡이) 표시
  • thumb 드래그로 값 조절
  • 값이 실시간으로 --progress-value CSS 변수에 반영되어 진행 바가 채워짐

3. <input type="range"> / 다른 입력 컴포넌트와의 차이

항목HTML rangeVa.SliderVa.Number

입력 방식 드래그 드래그 + 숫자 입력창 병기 숫자 타이핑 + 스피너
진행 바 색상 커스텀 ✕ (OS 스타일) ✓ (progressColor/railColor)
thumb 위 값 표시 ✓ (thumbText)
min/max 라벨 ✓ (visibleMinMax)
키보드 조작 화살표 화살표 (thumb에 tabindex) 화살표
접근성 표준 role="slider" 자동

한 줄 요약: "표준 range의 시각을 커스텀 가능하게 확장한 버전."


4. 주요 속성

범위·스텝

속성기본값설명

value 0 현재 값
min 최솟값
max 최댓값
step 증감 단위 (0.1, 1, 10 등)

표시 옵션

속성기본값설명

visibleCurrentValue 우측에 숫자 입력창 표시 여부
visibleMinMax min/max 라벨 표시 여부
thumbText thumb 위 값 표시 여부
inputWidth 80 숫자 입력창 폭 (px)

색상 커스터마이즈

속성기본값설명

progressColor 채워진 진행 바 색상 (CSS 색값)
railColor 빈 rail 색상

CSS 변수 --progress-color, --rail-color로 반영됩니다.

PureField 상속

readonly, disabled, size, appearance, stopPropagation 등 표준.


5. 이벤트

이벤트시그니처발생 시점

change (component, element, value, evt) thumb 드래그로 값 변경 시
blur (component, element, value, evt) 숫자 입력창에서 blur 시 (값 확정)
click (component, element, evt) 클릭
focus (component, element, evt) 포커스 진입
keydown (component, element, keyCode, evt) thumb에 포커스된 상태의 키
contextmenu (component, element, evt) 우클릭

주목: 두 종류의 변경 시나리오 — thumb 드래그(change)와 숫자 입력창 편집(blur)이 각각 다른 이벤트로 dispatch됩니다.

change 콜백 예시

onVolumeChange(comp, el, value, evt) {
    console.log('현재 값:', value);   // 문자열로 옴 (input type=range 특성)
    audio.volume = Number(value) / 100;
}

⚠️ value가 문자열 — <input type="range">는 값이 항상 문자열입니다. 계산 시 Number() 변환.


6. 메서드

값 관리

메서드설명

setValue(value) 값 세팅 + thumb 위치·진행 바·숫자 입력창 모두 자동 갱신
getValue() 현재 값 반환 (PureField 상속, 문자열)

상태·포커스

메서드설명

setDisabled(bool) / setReadOnly(bool) PureField 상속
focus() thumb 요소에 포커스 (실제 <input> 아님)
blur() thumb 블러

7. 내부 구조

<div elname="element" class="va-slider [size]..." va-role="va-slider">
  <div elname="fieldWrapper" class="field-wrapper" role="slider">
    <div elname="sliderDiv" class="slider-div"
         style="--progress-value: 50%; --progress-color: ...; --rail-color: ...">
      <input elname="field" type="range" class="slider" tabindex="-1">
      <div elname="rail" class="slider-rail"></div>
      <div elname="thumb" class="slider-thumb" tabindex="0">
        <div elname="thumbText" class="slider-thumb-text">50</div>
      </div>
    </div>
    <div cpname="inputValue" class="va-number">…</div>   ← visibleCurrentValue일 때
  </div>
</div>

핵심:

  • CSS 변수(--progress-value)로 진행 바 표현 — thumb 위치가 이 값으로 결정
  • thumb가 tabindex=0 — 실제 키보드 포커스 대상. <input type="range">는 tabindex=-1로 숨겨짐
  • 숫자 입력창은 내부 Va.Number 인스턴스  visibleCurrentValue 옵션에 따라 표시/숨김

8. Slider 계열 형제 컴포넌트

va_slider.js에 함께 정의되어 있는 슬라이더 변형들:

컴포넌트역할

Va.Slider 단일 값 슬라이더 (이 문서)
Va.DoubleSlider 범위 슬라이더 (min-max 두 thumb)
Va.StarSlider 별점 슬라이더 (0~5 별 UI)
(그 외 데이터 매핑 슬라이더) 배열 값에 매핑

9. 언제 쓰나

Slider가 맞을 때

  • 볼륨·밝기·투명도 등 연속 값 조절
  • 가격·나이 필터 (범위가 명확하고 대략적 값이면 충분)
  • 비율·퍼센트 조정
  • 사용자가 정확한 숫자보다 감각적 조절이 필요할 때
  • 진행 상황 시각화 (읽기 전용으로)

다른 걸 쓸 때

  • 정확한 숫자 입력 → Va.NumberField
  • 범위(from-to) 선택 → Va.DoubleSlider
  • 별점 → Va.StarSlider
  • 이산 옵션 선택 (2~5개) → Va.RadioGroup / Va.SegmentedControl

10. 흔한 조합 예시

// 표준 (숫자 입력창 병기)
{
    tagName: 'slider',
    value: 50,
    min: 0,
    max: 100,
    step: 1,
    visibleCurrentValue: true,
    onChange: 'onChange'
}

// 소수점 단위 (평점 등)
{
    tagName: 'slider',
    value: 3.5,
    min: 0,
    max: 5,
    step: 0.1,
    visibleCurrentValue: true,
    inputWidth: 60
}

// min/max 라벨 표시
{
    tagName: 'slider',
    value: 20,
    min: 0,
    max: 100,
    visibleMinMax: true,
    thumbText: true
}

// 색상 커스텀 (브랜드 컬러)
{
    tagName: 'slider',
    value: 60,
    min: 0,
    max: 100,
    progressColor: '#0f6cbd',
    railColor: '#e0e0e0'
}

// 볼륨 컨트롤 (아이콘과 함께)
{
    tagName: 'div',
    layout: 'ds-flex fd-row ai-center gap-s',
    tags: [
        { tagName: 'i', class: 'ico_speaker' },
        {
            tagName: 'slider',
            ref: 'volume',
            value: 70,
            min: 0,
            max: 100,
            style: { flex: 1 }
        }
    ]
}

// 읽기 전용 (진행률 표시)
{
    tagName: 'slider',
    value: 45,
    min: 0,
    max: 100,
    readonly: true,
    thumbText: true
}

11. 실전 예 — 필터 슬라이더

class PriceFilter extends Va.View {
    mounted() {
        this.applyFilter(this.getRef('price').getValue());
    }

    onPriceChange(comp, el, value, evt) {
        this.applyFilter(Number(value));
    }

    applyFilter(maxPrice) {
        this.getRef('label').setValue(maxPrice.toLocaleString() + '원 이하');
        // 상품 목록 필터링
        ProductService.search(this, { maxPrice }, (view, ok, res) => {
            if (ok) view.getRef('grid').setData(res.data.list);
        });
    }

    config() {
        return {
            tagName: 'page',
            tags: [{
                tagName: 'panel',
                tags: [
                    { tagName: 'h2', innerHTML: '가격대 필터' },
                    {
                        tagName: 'slider',
                        ref: 'price',
                        value: 50000,
                        min: 0,
                        max: 200000,
                        step: 10000,
                        visibleCurrentValue: true,
                        visibleMinMax: true,
                        progressColor: '#0f6cbd',
                        onChange: 'onPriceChange'
                    },
                    { tagName: 'div', ref: 'label', innerHTML: '' },
                    { tagName: 'grid', ref: 'grid', columns: [/* ... */] }
                ]
            }]
        };
    }
}

12. 알아두면 좋을 주의사항

  1. va_slider.js import 필수 — 이거 안 하면 tagName:'slider' 인식 못 함.
  2. value는 문자열로 반환  <input type="range"> 특성. 계산 시 Number() 변환.
  3. step이 없으면 소수점까지 세밀 조절 — 정수만 원하면 step: 1 명시.
  4. min/max 필수 정도의 옵션 — 없으면 진행 바 계산에서 NaN 발생 위험 (0/(max-min)).
  5. focus()는 thumb에 포커스 — 실제 <input> 아님. 키보드 화살표로 조절 가능.
  6. visibleCurrentValue: true면 숫자 입력창 추가 — 폭이 늘어나니 부모 layout 고려.
  7. inputWidth 기본 80 — 좁으면 값이 잘림. 3자리 이상은 100 권장.
  8. 진행 바 색상은 CSS 변수  progressColor/railColor 옵션 없이 CSS로 직접 --progress-color 오버라이드도 가능.
  9. change가 드래그 중 계속 발생 — 성능 걱정되면 debounce 필요.
  10. mousemove도 내부에서 사용 — 슬라이더 위 마우스 이동 시 값 갱신. thumb 아닌 rail 위에서도 반응.
  11. 접근성  role="slider" 자동. 스크린리더 인식 가능하지만 aria-valuemin/aria-valuemax/aria-valuenow는 명시 세팅 필요.
  12. preventParentFieldEvent: true 강제 — 생성자에서 옵션에 강제 설정 (va_slider.js:30). 부모 Field 이벤트가 슬라이더 조작에 개입 못 하게 함.

13. slider vs numberField vs doubleSlider 선택

상황추천

연속 값 감각적 조절 (볼륨 등) slider
정확한 숫자 입력 numberField
범위(from-to) 선택 doubleSlider
별점 starSlider
이산 옵션 몇 개 radioGroup
큰 숫자 정밀 입력 numberField + numberComma

"드래그로 조절이 자연스러우면 slider, 정확한 숫자면 numberField" — 기본 원칙.


참고