컴포넌트/필드 컴포넌트

StarSlider (스타슬라이더)

VanillaFront 2026. 9. 13. 23:41

Va.StarSlider — 별점 입력 컴포넌트

별 아이콘을 클릭해서 점수를 매기는 별점 입력 컴포넌트. 리뷰·평점 UI의 표준 형태. 별 개수, 색상, 최댓값 매핑까지 옵션으로 커스터마이즈됩니다.

  • 클래스: Va.StarSlider  va_slider.js:512
  • short name: starSlider
  • 상속: Va.PureField (Slider·Input과 형제)
  • 파일: va_slider.js (별도 파일 — import 필요)
  • isContainer: true


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

import Va from '../../lib/va.js';
import '../../lib/va_slider.js';       // ← Slider 계열 모두 이 파일에

2. 기본 사용

{
    tagName: 'starSlider',
    value: 3,
    starCount: 5,
    onChange: 'onRatingChange'
}
  • 별 5개 표시 (기본)
  • 3번째까지 채워진 별로 렌더
  • 별 클릭 시 그 위치까지 채워짐

3. Slider / StarSlider의 차이

항목Va.SliderVa.StarSlider

UI 형태 rail + thumb (드래그) 별 아이콘 클릭
값 형태 연속 수치 정수 (별 개수) 또는 매핑값
기본 범위 min/max 필수 1 ~ starCount (기본 1~5)
starCount ✓ (별 개수)
starColor ✓ (별 색상)
max 필수 선택 (매핑용)
입력 방식 드래그 클릭

한 줄 요약: "별점을 클릭으로 매기는 리뷰용 컴포넌트."


4. 주요 속성

별 관련

속성기본값설명

value 0 현재 별점 값
starCount 5 표시할 별 개수
starColor 'orange' 채워진 별 색상
starDisabledColor 'var(--colorStrokeDisabled)' 비활성 상태 별 색상

표시 옵션

속성설명

visibleValue 별 옆에 현재 값 숫자 표시

최댓값 매핑 (선택)

속성설명

max 지정 시 별 개수와 별개로 값 범위 매핑. 예: 별 5개, max: 100 → 3번째 별 클릭 = 60

PureField 상속

readonly, disabled, size, appearance, stopPropagation 등.


5. max 옵션의 정체 — 별 개수 vs 실제 값

기본 동작: starCount: 5면 값이 1~5

하지만 max를 지정하면 매핑:

{
    tagName: 'starSlider',
    starCount: 5,
    max: 100          // 별 5개가 0~100을 표현
}
// 별 3개 클릭 → value = 3 * 100 / 5 = 60

언제 쓰나:

  • UI는 별 5개로 보여주고 싶은데
  • 저장 값은 100점 만점 같은 다른 스케일

리뷰 UI에서 흔한 요구사항 대응용.


6. 이벤트

이벤트시그니처발생 시점

change (component, element, value, evt) 별 클릭으로 값 변경 시. value는 새 별점
click (component, element, evt) 클릭 (change 직전에 dispatch)
focus / blur (component, element, evt) 별 포커스 진입/이탈
contextmenu (component, element, evt) 우클릭

change 콜백 예시

onRatingChange(comp, el, value, evt) {
    console.log('별점:', value);   // 3 (기본) 또는 60 (max:100 매핑 시)
    ReviewService.save(this, { rating: value }, ...);
}

주목: Slider와 달리 value가 숫자로 오는 게 자연스러움 (내부에서 계산 결과). 다만 max 매핑 시 소수점이 발생할 수 있음.


7. 메서드

값 관리

메서드설명

setValue(value) 별점 세팅 + 즉시 별 아이콘 재렌더
getValue() 현재 값 반환

상태 (PureField 상속)

메서드설명

setDisabled(bool) / setReadOnly(bool) 상태 (별 색상도 disabled 색으로 자동 전환)

주의: focus() 편의 메서드 없음. 각 별에 tabindex=0이라 표준 Tab 키로 탐색은 가능.


8. 내부 구조

<div elname="element" class="va-star-slider" ...>
  <div elname="fieldWrapper" class="field-wrapper">
    <div elname="starDiv" class="star-div">
      <span class="icon ico_star_fill" tabindex="0"
            style="background-color: orange">★</span>       ← 채워진 별
      <span class="icon ico_star_fill" tabindex="0" style="...">★</span>
      <span class="icon ico_star_fill" tabindex="0" style="...">★</span>
      <span class="icon ico_star" tabindex="0" style="...">☆</span>      ← 빈 별
      <span class="icon ico_star" tabindex="0" style="...">☆</span>
    </div>
    <div elname="currValue" class="value-div"
         style="display:none">3</div>                       ← visibleValue일 때 표시
  </div>
</div>

핵심:

  • 채워진 별: ico_star_fill 클래스
  • 빈 별: ico_star 클래스
  • 각 별에 tabindex=0 — 키보드 포커스 가능
  • 인라인 style로 색상 지정  starColor / starDisabledColor

9. Va.Slider 계열과의 관계

va_slider.js에 함께 정의된 슬라이더 계열들:

컴포넌트역할

Va.Slider 단일 값 드래그 슬라이더
Va.DoubleSlider 범위 슬라이더 (2개 thumb)
Va.StarSlider 별점 (이 문서)
Va.SliderField Slider + Field 래퍼
Va.StarSliderField StarSlider + Field 래퍼

10. 언제 쓰나

StarSlider가 맞을 때

  • 리뷰 평점 입력 (숙소, 상품, 콘텐츠)
  • 만족도 조사 (1~5 별점)
  • 품질 평가 (내부 관리 화면)
  • 사용자가 직관적으로 "몇 개짜리 별점"으로 표현하고 싶은 상황

다른 걸 쓸 때

  • 정확한 수치 입력 → Va.NumberField
  • 감각적 슬라이더 → Va.Slider
  • 아이콘이 별이 아닌 (하트, 좋아요 등) → 커스텀 필요 (star 아이콘 하드코딩)
  • 배타 선택 라디오형 → Va.RadioGroup
  • 라벨 붙은 폼 필드 → Va.StarSliderField

11. 흔한 조합 예시

// 표준 5점 별점
{
    tagName: 'starSlider',
    value: 3,
    visibleValue: true
}

// 10개 별
{
    tagName: 'starSlider',
    starCount: 10,
    value: 7
}

// 색상 커스텀
{
    tagName: 'starSlider',
    value: 4,
    starColor: '#ff6b6b',
    starDisabledColor: '#dddddd'
}

// 100점 만점 매핑
{
    tagName: 'starSlider',
    starCount: 5,
    max: 100,           // 별 5개가 0~100 표현
    value: 80           // → 4번째 별까지 채워짐
}

// 읽기 전용 (평점 표시용)
{
    tagName: 'starSlider',
    value: 4.5,
    readonly: true,
    starColor: '#f8b400'
}

// 브랜드 컬러
{
    tagName: 'starSlider',
    value: 3,
    starColor: 'var(--colorBrandStroke1)'
}

12. 실전 예 — 리뷰 폼

class ReviewForm extends Va.View {
    onRatingChange(comp, el, value, evt) {
        // 별점 변경 시 텍스트 업데이트
        const labels = { 1: '나빠요', 2: '별로', 3: '보통', 4: '좋아요', 5: '최고!' };
        this.getRef('label').setValue(labels[value] || '');
    }

    onSubmit(btn, el, evt) {
        const rating  = this.getRef('rating').getValue();
        const comment = this.getRef('comment').getValue();

        if (rating === 0) {
            new Va.Alert({ title: '알림', message: '별점을 선택하세요' }).show(this);
            return;
        }

        ReviewService.save(this, { rating, comment }, (view, ok) => {
            if (ok) new Va.Alert({ title: '완료', message: '리뷰가 등록되었습니다' }).show(view);
        });
    }

    config() {
        return {
            tagName: 'page',
            tags: [{
                tagName: 'panel',
                tags: [
                    { tagName: 'h2', innerHTML: '리뷰 작성' },
                    {
                        tagName: 'div',
                        layout: 'ds-flex fd-row ai-center gap-m',
                        tags: [
                            {
                                tagName: 'starSlider',
                                ref: 'rating',
                                value: 0,
                                starCount: 5,
                                starColor: '#f8b400',
                                onChange: 'onRatingChange'
                            },
                            { tagName: 'div', ref: 'label', innerHTML: '' }
                        ]
                    },
                    {
                        tagName: 'textareaField',
                        ref: 'comment',
                        label: '리뷰',
                        placeholder: '의견을 남겨주세요'
                    },
                    {
                        tagName: 'button',
                        text: '등록',
                        appearance: 'primary',
                        onClick: 'onSubmit'
                    }
                ]
            }]
        };
    }
}

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

  1. va_slider.js import 필수 — 없으면 인식 못 함.
  2. value 기본이 0 — 아무 별도 안 채워진 상태. 옵션 미지정 시 조심.
  3. max 매핑 시 소수점 발생 가능  starCount: 5, max: 100, 별 2개 클릭 → 40(정수) but starCount: 5, max: 7, 별 3개 → 4.2 같은 상황.
  4. 별 아이콘 하드코딩  ico_star / ico_star_fill 클래스만 지원. 하트 등 다른 아이콘 쓰려면 소스 커스터마이즈.
  5. starColor가 인라인 style — CSS 변수 오버라이드보다 우선. 다크 테마 대응 시 유의.
  6. readonly: true도 클릭 반응 없음 — 소스에서 명시 return.
  7. 각 별에 tabindex=0 — Tab 키로 별 사이 이동 가능. 화살표 그룹 네비 없음.
  8. getValue()는 그대로 필드 값 — 문자열 변환 없음. Slider와 달리 숫자로 옴.
  9. 접근성 취약  role="radiogroup"이나 aria-valuenow 자동 세팅 없음. 스크린리더 대응이 약함.
  10. starCount 동적 변경 미지원 — 초기 생성 시 별 element를 만들어두고 재생성 로직 없음. starCount 바꿔서 update()해도 별 개수는 그대로.

14. starSlider vs 다른 평점 UI 선택

상황추천

리뷰·별점 (5점 표준) starSlider
정밀한 점수 (0~10, 소수점) slider + visibleCurrentValue
좋아요/싫어요 이진 toggleButton (하트 아이콘)
선호도 (매우 나쁨~매우 좋음 5단계) radioGroup 또는 segmentedControl
폼 안 라벨 붙은 별점 starSliderField

참고

'컴포넌트 > 필드 컴포넌트' 카테고리의 다른 글

Switch (스위치)  (0) 2026.09.13
StarSliderField (스타슬라이더필드)  (0) 2026.09.13
DoubleSlider (더블슬라이더)  (0) 2026.09.13
SliderField (슬라이더 필드)  (0) 2026.09.12
Slider (슬라이더)  (0) 2026.09.12