콘텐츠로 이동

checkbox —— 체크박스

체크박스는 폼 안의 가장 작은 상태기계입니다: 하나의 값이 배열 안에 있는지 없는지. core/checkbox에는 함수가 두 개뿐인데, “체크”를 집합 연산으로 추상했기 때문입니다——체크박스 그룹의 값은 하나의 배열이며, 체크는 원소를 추가하는 것이고 해제는 원소를 삭제하는 것입니다.

  • 각 말단 구현 LhCheckbox와 LhCheckboxGroup (group이 값 배열을 가지고, item이 그 안에서 자기 체크 상태를 판정).
  • 다중 선택 상황; 두 상태 스위치는 switch가 더 어울립니다.
  • 사용하면 안 되는 경우: 단일 선택은 radio; 반쪽 선택 의미 (부모 노드가 일부 체크됨)가 필요하면 tree의 체크 연동을 사용.
import { isCheckboxChecked, toggleCheckboxValue } from '@lh-ui/share/core/checkbox'
import type { LhCheckboxState } from '@lh-ui/share/core/checkbox'

includes의 암묵적 동등 판정이 아닌 Object.is로 판정하는 이유는, 체크박스의 값이 임의의 타입이 될 수 있기 때문입니다 (문자열, 숫자, 심지어 객체 참조). includes는 NaN에 false를 반환하지만 Object.is(NaN, NaN)은 true를 반환합니다——실제 상황에서는 드물지만, 집합의 의미는 일관되어야 합니다.

toggleCheckboxValue는 불변입니다: 먼저 같은 값을 가진 항목을 걸러내고 (중복 제거), 그 다음 checked에 따라 추가할지 결정합니다. 이 순서가 멱등성을 보장합니다——같은 값, 같은 방향으로 반복 호출해도 결과가 같으며, 배열에 중복 원소가 생기지 않습니다.

함수 시그니처 반환 역할
isCheckboxChecked (values: unknown[], value: unknown) => boolean 불리언 value가 배열 안에 있는지
toggleCheckboxValue (values: unknown[], value: unknown, checked: boolean) => unknown[] 새 배열 불변 토글
export interface LhCheckboxState {
values: unknown[]
value: unknown
checked: boolean
}

core/checkbox는 aria 속성 팩을 출력하지 않습니다——각 말단에서 브라우저 고유 <input type="checkbox">를 사용할 것을 강력히 권장합니다: 고유 요소는 aria-checked가 내장되어 있고 키보드 조작을 지원하며 폼 제출 의미까지 갖추고 있어, 어떤 커스텀 컨트롤의 등가 구현도 완전히 재현하기 어렵습니다.

브라우저 고유 checkbox의 indeterminate (반쪽 선택) 상태는 JS로만 설정할 수 있습니다 (대응하는 HTML 속성이 없음), 이것이 group 상황에서 UI 계층이 처리해야 할 유일한 특수점입니다:

// 부모 체크박스의 반쪽 선택 상태 (예: "전체 선택" 박스)
input.indeterminate = checkedCount > 0 && checkedCount < total
import { isCheckboxChecked, toggleCheckboxValue } from '@lh-ui/share/core/checkbox'
isCheckboxChecked(['a', 'b'], 'b') // true
isCheckboxChecked(['a', 'b'], 'c') // false
toggleCheckboxValue(['a', 'b'], 'c', true) // ['a', 'b', 'c']
toggleCheckboxValue(['a', 'b', 'c'], 'b', false) // ['a', 'c']
toggleCheckboxValue(['a', 'b'], 'b', false) // ['a']
toggleCheckboxValue(['a'], 'a', true) // ['a'] (이미 있음, 멱등)
<!-- Vue3: LhCheckboxGroup -->
<script setup>
const model = defineModel<Array<string>>({ default: [] })
const toggle = (value: string, checked: boolean) => {
model.value = toggleCheckboxValue(model.value, value, checked)
}
</script>
<template>
<div class="lh-checkbox-group" :class="`lh-checkbox-group--${size}`">
<label
v-for="opt in options"
:key="String(opt.value)"
class="lh-checkbox"
:class="{
'lh-checkbox--checked': isCheckboxChecked(model, opt.value),
'lh-checkbox--disabled': disabled || opt.disabled,
}"
>
<span class="lh-checkbox__box">
<input
class="lh-checkbox__input"
type="checkbox"
:checked="isCheckboxChecked(model, opt.value)"
:disabled="disabled || opt.disabled"
@change="toggle(opt.value, ($event.target as HTMLInputElement).checked)"
/>
</span>
<span class="lh-checkbox__label">{{ opt.label }}</span>
</label>
</div>
</template>
// React
const [values, setValues] = useState<string[]>([])
return options.map((opt) => (
<label key={opt.value} className="lh-checkbox">
<input
type="checkbox"
checked={isCheckboxChecked(values, opt.value)}
onChange={(e) => setValues(toggleCheckboxValue(values, opt.value, e.target.checked))}
/>
<span className="lh-checkbox__label">{opt.label}</span>
</label>
))
// uniapp: <checkbox-group> + <checkbox>는 내장 컴포넌트, change 이벤트가 곧바로 값 배열을 줌;
// 커스텀 체크 스타일은 .lh-checkbox__box로 기본 외관 덮어쓰기 (h5가 아닌 말단에서는 :checked의 반응성 주의)
클래스명 의미
.lh-checkbox 기본 클래스 (label 래퍼)
.lh-checkbox--checked / --indeterminate / --disabled 세 상태
.lh-checkbox--{small|large} 크기 단계
.lh-checkbox__box 커스텀 체크 박스 (브라우저 고유 외관 덮어쓰기)
.lh-checkbox__input 고유 input (시각적으로 숨김, 의미는 유지)
.lh-checkbox__label 글자
.lh-checkbox-group / --{small|large} 그룹 컨테이너와 그룹 크기

체크 표시의 위치 지정은 고정된 top: 2px / left: 5px입니다——16px 박스에서만 정확하며, 이것은 “높이 토큰 특별 작업”에 기록된 통일 대기 항목입니다 (50% 가운데 정렬로 바뀌어야 함).

  • 값의 타입 일관성: toggleCheckboxValue(['1'], 1, true)는 ['1', 1]을 반환합니다——문자열 '1'과 숫자 1은 두 개의 다른 값입니다. 백엔드가 주는 id 타입은 UI 계층에서 반드시 통일해야 합니다.
  • 빈 배열의 의미: values: []는 “아무것도 선택하지 않음”이며 values: undefined와 다릅니다; group의 기본값은 []여야 합니다.
  • checked 매개변수의 방향: 이것은 “현재 상태”가 아닌 “목표 상태”이며, toggleCheckboxValue(v, x, false)는 원래 있었는지와 무관하게 반드시 x를 제거합니다.
  • 옵션이 많을 때 virtual-list를 고려하세요; group 자체는 가상화하지 않습니다.
@lh-ui/share/core/checkbox → toggleCheckboxValue( )
返回值
(填好参数后点运行)

Copyright © 2024-2026 FengMo WenXue