Skip to content
API 风格:

Cascader 계단식 선택기 ​

계단식 선택기는 여러 계층의 데이터를 다루는 상황에 사용합니다. 예를 들어 성/시/구역 선택이 있습니다.

기본 사용법 ​

독립적으로 사용
vue
<script setup>
import { ref } from 'vue'

const value1 = ref([])
const options1 = [
  {
    value: 'zhinan',
    label: '가이드',
    children: [
      {
        value: 'sheji',
        label: '디자인 가이드',
        children: [
          { value: 'yuansze', label: '색상' },
          { value: 'fuziyuanze', label: '글꼴' },
        ],
      },
      {
        value: 'shejiguize',
        label: '디자인 규칙',
      },
    ],
  },
  {
    value: 'zujian',
    label: '컴포넌트',
    children: [
      { value: 'jiben', label: '기본' },
      { value: 'fankui', label: '피드백' },
    ],
  },
]
</script>

<template>
  <!-- 기본 사용법 -->
  <lh-cascader v-model="value1" :options="options1" />
</template>
vue
<script>
export default {
  data() {
    return {
      value1: [],
      options1: [
        {
          value: 'zhinan',
          label: '가이드',
          children: [
            {
              value: 'sheji',
              label: '디자인 가이드',
              children: [
                { value: 'yuansze', label: '색상' },
                { value: 'fuziyuanze', label: '글꼴' },
              ],
            },
            {
              value: 'shejiguize',
              label: '디자인 규칙',
            },
          ],
        },
        {
          value: 'zujian',
          label: '컴포넌트',
          children: [
            { value: 'jiben', label: '기본' },
            { value: 'fankui', label: '피드백' },
          ],
        },
      ],
    }
  },
}
</script>

<template>
  <!-- 기본 사용법 -->
  <lh-cascader v-model="value1" :options="options1" />
</template>

다중 선택 모드 ​

다중 선택 모드로 설정하면 여러 결과를 선택할 수 있습니다.

다중 선택 모드
vue
<script setup>
import { ref } from 'vue'

const value2 = ref([])
const options2 = [
  {
    value: 'zhinan',
    label: '가이드',
    children: [
      { value: 'sheji', label: '디자인 가이드' },
      { value: 'shejiguize', label: '디자인 규칙' },
    ],
  },
  {
    value: 'zujian',
    label: '컴포넌트',
    children: [
      { value: 'jiben', label: '기본 컴포넌트' },
      { value: 'fankui', label: '피드백 컴포넌트' },
    ],
  },
]
</script>

<template>
  <!-- 다중 선택 모드 -->
  <lh-cascader v-model="value2" :options="options2" multiple />
</template>
vue
<script>
export default {
  data() {
    return {
      value2: [],
      options2: [
        {
          value: 'zhinan',
          label: '가이드',
          children: [
            { value: 'sheji', label: '디자인 가이드' },
            { value: 'shejiguize', label: '디자인 규칙' },
          ],
        },
        {
          value: 'zujian',
          label: '컴포넌트',
          children: [
            { value: 'jiben', label: '기본 컴포넌트' },
            { value: 'fankui', label: '피드백 컴포넌트' },
          ],
        },
      ],
    }
  },
}
</script>

<template>
  <!-- 다중 선택 모드 -->
  <lh-cascader v-model="value2" :options="options2" multiple />
</template>

옵션 비활성화 ​

disabled 속성으로 노드를 비활성화합니다.

옵션 비활성화
vue
<script setup>
import { ref } from 'vue'

const value3 = ref([])
const options3 = [
  {
    value: 'zhinan',
    label: '가이드',
    disabled: true,
    children: [
      { value: 'sheji', label: '디자인 가이드' },
    ],
  },
  {
    value: 'zujian',
    label: '컴포넌트',
    children: [
      { value: 'jiben', label: '기본 컴포넌트' },
      { value: 'fankui', label: '피드백 컴포넌트', disabled: true },
    ],
  },
]
</script>

<template>
  <!-- 옵션 비활성화 -->
  <lh-cascader v-model="value3" :options="options3" />
</template>
vue
<script>
export default {
  data() {
    return {
      value3: [],
      options3: [
        {
          value: 'zhinan',
          label: '가이드',
          disabled: true,
          children: [
            { value: 'sheji', label: '디자인 가이드' },
          ],
        },
        {
          value: 'zujian',
          label: '컴포넌트',
          children: [
            { value: 'jiben', label: '기본 컴포넌트' },
            { value: 'fankui', label: '피드백 컴포넌트', disabled: true },
          ],
        },
      ],
    }
  },
}
</script>

<template>
  <!-- 옵션 비활성화 -->
  <lh-cascader v-model="value3" :options="options3" />
</template>

크기, 비활성화, 읽기 전용 ​

size로 크기를 조정하고, disabled로 선택기 전체를 비활성화하고, readonly로 읽기 전용 표시하고, placeholder로 플레이스홀더를 지정하고, clearable로 초기화 버튼을 끕니다.

크기, 비활성화, 읽기 전용
vue
<script setup lang="ts">
import { ref } from 'vue'

const demoCascSize = ref([])
const demoCascSize2 = ref([])
const demoCascDisabled = ref([])
const demoCascReadonly = ref([])
const demoCascPlaceholder = ref([])
const demoCascNoClear = ref([])
const options = [
  {
    value: 'zhinan',
    label: '가이드',
    children: [
      { value: 'sheji', label: '디자인 가이드' },
      { value: 'shejiguize', label: '디자인 규칙' },
    ],
  },
  {
    value: 'zujian',
    label: '컴포넌트',
    children: [
      { value: 'jiben', label: '기본 컴포넌트' },
      { value: 'fankui', label: '피드백 컴포넌트' },
    ],
  },
]
</script>

<template>
  <!-- small -->
  <lh-cascader v-model="demoCascSize" :options="options" size="small" placeholder="small" />
  <!-- large -->
  <lh-cascader v-model="demoCascSize2" :options="options" size="large" placeholder="large" />
  <!-- 비활성화 상태 -->
  <lh-cascader v-model="demoCascDisabled" :options="options" disabled placeholder="비활성화 상태" />
  <!-- 읽기 전용 상태 -->
  <lh-cascader v-model="demoCascReadonly" :options="options" readonly placeholder="읽기 전용 상태" />
  <!-- 커스텀 플레이스홀더 -->
  <lh-cascader v-model="demoCascPlaceholder" :options="options" placeholder="커스텀 플레이스홀더" />
  <!-- 초기화 불가 -->
  <lh-cascader v-model="demoCascNoClear" :options="options" :clearable="false" placeholder="초기화 불가" />
</template>
vue
<script>
export default {
  data() {
    return {
      demoCascSize: [],
      demoCascSize2: [],
      demoCascDisabled: [],
      demoCascReadonly: [],
      demoCascPlaceholder: [],
      demoCascNoClear: [],
      options: [
        {
          value: 'zhinan',
          label: '가이드',
          children: [
            { value: 'sheji', label: '디자인 가이드' },
            { value: 'shejiguize', label: '디자인 규칙' },
          ],
        },
        {
          value: 'zujian',
          label: '컴포넌트',
          children: [
            { value: 'jiben', label: '기본 컴포넌트' },
            { value: 'fankui', label: '피드백 컴포넌트' },
          ],
        },
      ],
    }
  },
}
</script>

<template>
  <!-- small -->
  <lh-cascader v-model="demoCascSize" :options="options" size="small" placeholder="small" />
  <!-- large -->
  <lh-cascader v-model="demoCascSize2" :options="options" size="large" placeholder="large" />
  <!-- 비활성화 상태 -->
  <lh-cascader v-model="demoCascDisabled" :options="options" disabled placeholder="비활성화 상태" />
  <!-- 읽기 전용 상태 -->
  <lh-cascader v-model="demoCascReadonly" :options="options" readonly placeholder="읽기 전용 상태" />
  <!-- 커스텀 플레이스홀더 -->
  <lh-cascader v-model="demoCascPlaceholder" :options="options" placeholder="커스텀 플레이스홀더" />
  <!-- 초기화 불가 -->
  <lh-cascader v-model="demoCascNoClear" :options="options" :clearable="false" placeholder="초기화 불가" />
</template>

경로 표시와 검색 ​

  • show-all-levels는 입력 상자에 전체 경로를 표시할지 제어합니다(기본값 true, 끄면 마지막 단계 이름만 표시).
  • separator로 경로 구분 기호를 지정하며, 검색 결과 패널에도 동일하게 적용됩니다.
  • emit-path를 false로 설정하면 v-model이 마지막 단계 노드의 값만 바인딩하고, 입력 상자에는 여전히 전체 경로가 표시됩니다.
  • check-strictly는 임의의 계층 노드를 선택할 수 있게 합니다(임의 계층을 클릭하면 바로 선택, 하위 계층 탐색은 마우스 오버로 펼침).
  • filterable로 검색을 켜면, 키워드를 입력해 전체 경로로 일치 항목을 보여줍니다.
  • collapse-tags는 다중 선택 모드에서 태그를 접습니다.
  • cascading으로 부모-자식 노드 연동 선택을 끕니다.
  • item-config로 노드 필드 별칭을 지정합니다(예: id / name으로 트리 구축), 경로 표시에도 동일하게 적용됩니다.

아래 예시는 모두 선택값을 미리 세팅해 두었으므로 단계별로 선택하지 않아도 차이를 바로 비교할 수 있습니다: 전체 경로 표시는 저장성/항저우시/시후구, show-all-levels를 끄면 시후구만, separator=" > "일 때는 저장성 > 항저우시 > 시후구로 표시합니다.

경로 표시와 검색
저장성/항저우시/시후구
+1
저장성/항저우시/시후구
저장성/항저우시/빈장구
vue
<script setup lang="ts">
import { ref } from 'vue'

const demoCascFullPath = ref(['zhejiang', 'hangzhou', 'xihu'])
const demoCascAllLevels = ref(['zhejiang', 'hangzhou', 'xihu'])
const demoCascSep = ref(['zhejiang', 'hangzhou', 'xihu'])
const demoCascEmit = ref(['xihu'])
const demoCascStrict = ref(['zhejiang', 'hangzhou'])
const demoCascFilter = ref([])
const demoCascCollapse = ref(['xihu', 'haishu'])
const demoCascLoose = ref(['xihu', 'binjiang'])
const demoCascItem = ref(['zhejiang', 'hangzhou', 'xihu'])

const pathOptions = [
  {
    value: 'zhejiang',
    label: '저장성',
    children: [
      {
        value: 'hangzhou',
        label: '항저우시',
        children: [
          { value: 'xihu', label: '시후구' },
          { value: 'binjiang', label: '빈장구' },
        ],
      },
      {
        value: 'ningbo',
        label: '닝보시',
        children: [{ value: 'haishu', label: '하이수구' }],
      },
    ],
  },
  {
    value: 'jiangsu',
    label: '장쑤성',
    children: [
      {
        value: 'nanjing',
        label: '난징시',
        children: [{ value: 'xuanwu', label: '쉬안우구' }],
      },
    ],
  },
]

const aliasedOptions = [
  {
    id: 'zhejiang',
    name: '저장성',
    sub: [
      {
        id: 'hangzhou',
        name: '항저우시',
        sub: [
          { id: 'xihu', name: '시후구' },
          { id: 'binjiang', name: '빈장구' },
        ],
      },
      {
        id: 'ningbo',
        name: '닝보시',
        sub: [{ id: 'haishu', name: '하이수구' }],
      },
    ],
  },
]
</script>

<template>
  <!-- 전체 경로(기본값) -->
  <lh-cascader v-model="demoCascFullPath" :options="pathOptions" placeholder="전체 경로(기본값)" />
  <!-- 마지막 단계만 표시 -->
  <lh-cascader v-model="demoCascAllLevels" :options="pathOptions" :show-all-levels="false" placeholder="마지막 단계만 표시" />
  <!-- 구분 기호 > -->
  <lh-cascader v-model="demoCascSep" :options="pathOptions" separator=" > " placeholder="구분 기호 >" />
  <!-- 마지막 단계 값만 반환 -->
  <lh-cascader v-model="demoCascEmit" :options="pathOptions" :emit-path="false" placeholder="마지막 단계 값만 반환" />
  <!-- 임의 계층 선택 가능 -->
  <lh-cascader v-model="demoCascStrict" :options="pathOptions" check-strictly placeholder="임의 계층 선택 가능" />
  <!-- 검색 가능 -->
  <lh-cascader v-model="demoCascFilter" :options="pathOptions" filterable placeholder="검색 가능" />
  <!-- 다중 선택 태그 접기 -->
  <lh-cascader v-model="demoCascCollapse" :options="pathOptions" multiple collapse-tags placeholder="다중 선택 태그 접기" />
  <!-- 부모-자식 미연동 -->
  <lh-cascader v-model="demoCascLoose" :options="pathOptions" multiple :cascading="false" placeholder="부모-자식 미연동" />
  <!-- 필드 별칭 -->
  <lh-cascader v-model="demoCascItem" :options="aliasedOptions" :item-config="{ value: 'id', label: 'name', children: 'sub' }" placeholder="필드 별칭" />
</template>
vue
<script>
export default {
  data() {
    return {
      demoCascFullPath: ['zhejiang', 'hangzhou', 'xihu'],
      demoCascAllLevels: ['zhejiang', 'hangzhou', 'xihu'],
      demoCascSep: ['zhejiang', 'hangzhou', 'xihu'],
      demoCascEmit: ['xihu'],
      demoCascStrict: ['zhejiang', 'hangzhou'],
      demoCascFilter: [],
      demoCascCollapse: ['xihu', 'haishu'],
      demoCascLoose: ['xihu', 'binjiang'],
      demoCascItem: ['zhejiang', 'hangzhou', 'xihu'],
      pathOptions: [
        {
          value: 'zhejiang',
          label: '저장성',
          children: [
            {
              value: 'hangzhou',
              label: '항저우시',
              children: [
                { value: 'xihu', label: '시후구' },
                { value: 'binjiang', label: '빈장구' },
              ],
            },
            {
              value: 'ningbo',
              label: '닝보시',
              children: [{ value: 'haishu', label: '하이수구' }],
            },
          ],
        },
        {
          value: 'jiangsu',
          label: '장쑤성',
          children: [
            {
              value: 'nanjing',
              label: '난징시',
              children: [{ value: 'xuanwu', label: '쉬안우구' }],
            },
          ],
        },
      ],
      aliasedOptions: [
        {
          id: 'zhejiang',
          name: '저장성',
          sub: [
            {
              id: 'hangzhou',
              name: '항저우시',
              sub: [
                { id: 'xihu', name: '시후구' },
                { id: 'binjiang', name: '빈장구' },
              ],
            },
            {
              id: 'ningbo',
              name: '닝보시',
              sub: [{ id: 'haishu', name: '하이수구' }],
            },
          ],
        },
      ],
    }
  },
}
</script>

<template>
  <!-- 전체 경로(기본값) -->
  <lh-cascader v-model="demoCascFullPath" :options="pathOptions" placeholder="전체 경로(기본값)" />
  <!-- 마지막 단계만 표시 -->
  <lh-cascader v-model="demoCascAllLevels" :options="pathOptions" :show-all-levels="false" placeholder="마지막 단계만 표시" />
  <!-- 구분 기호 > -->
  <lh-cascader v-model="demoCascSep" :options="pathOptions" separator=" > " placeholder="구분 기호 >" />
  <!-- 마지막 단계 값만 반환 -->
  <lh-cascader v-model="demoCascEmit" :options="pathOptions" :emit-path="false" placeholder="마지막 단계 값만 반환" />
  <!-- 임의 계층 선택 가능 -->
  <lh-cascader v-model="demoCascStrict" :options="pathOptions" check-strictly placeholder="임의 계층 선택 가능" />
  <!-- 검색 가능 -->
  <lh-cascader v-model="demoCascFilter" :options="pathOptions" filterable placeholder="검색 가능" />
  <!-- 다중 선택 태그 접기 -->
  <lh-cascader v-model="demoCascCollapse" :options="pathOptions" multiple collapse-tags placeholder="다중 선택 태그 접기" />
  <!-- 부모-자식 미연동 -->
  <lh-cascader v-model="demoCascLoose" :options="pathOptions" multiple :cascading="false" placeholder="부모-자식 미연동" />
  <!-- 필드 별칭 -->
  <lh-cascader v-model="demoCascItem" :options="aliasedOptions" :item-config="{ value: 'id', label: 'name', children: 'sub' }" placeholder="필드 별칭" />
</template>

Props ​

속성설명타입기본값
modelValue바인딩값(string | number)[]() => []
options옵션 목록[LhCascaderNode](#type-LhCascaderNode)[]() => []
size크기"small" | "medium" | "large" | "mini" | "x-large"'medium'
disabled비활성화 여부booleanfalse
clearable초기화 가능 여부booleantrue
placeholder플레이스홀더(전달하지 않으면 언어 팩 cascader.placeholder 사용, 중국어 '请选择')string''
readonly읽기 전용 여부booleanfalse
showAllLevels입력 상자에 전체 경로 표시 여부booleantrue
checkStrictly임의 계층 노드 선택 가능booleanfalse
emitPath반환값에 전체 경로 포함 여부booleantrue
multiple다중 선택 여부booleanfalse
cascading계단식 연동 여부booleantrue
separator구분 기호string'/'
collapseTags다중 선택 모드에서 태그 접기 여부booleanfalse
filterable검색 가능 여부booleanfalse
itemConfig노드 필드 별칭[LhCascaderItemConfig](#type-LhCascaderItemConfig)() => ({})
sx빠른 레이아웃 속성(예: { mt: 2, w: '50%' }), 인라인 스타일로 변환되어 트리거 루트 요소에 적용(플로팅 패널은 영향을 받지 않음)LhSxProps—

Events ​

이벤트설명콜백 매개변수
change선택값이 변경될 때 발생(value: (string | number)[], path: LhCascaderNode[] | null)
update:model-value바인딩값이 변경될 때 발생value: (string | number)[]

데이터 구조 ​

LhCascaderNode 타입 정의:

ts
interface LhCascaderNode {
  value: string | number
  label: string
  disabled?: boolean
  leaf?: boolean
  children?: LhCascaderNode[]
}

타입 정의 ​

이 컴포넌트가 외부로 내보내는 TypeScript 타입 구조는 다음과 같습니다(packages/components/cascader/src/types.ts와 @lh-ui/share/core/* 소스에서 자동 추출, 각 항목을 펼쳐 전체 정의를 확인하세요. 속성 설명은 위쪽 Props 표를 참고하세요).

LhCascaderProps
ts
export interface LhCascaderProps {
  modelValue?: (string | number)[]
  options?: LhCascaderNode[]
  size?: LhComponentSize
  disabled?: boolean
  clearable?: boolean
  placeholder?: string
  readonly?: boolean
  showAllLevels?: boolean
  checkStrictly?: boolean
  emitPath?: boolean
  multiple?: boolean
  cascading?: boolean
  separator?: string
  collapseTags?: boolean
  filterable?: boolean
  itemConfig?: LhCascaderItemConfig
  /** sx 빠른 레이아웃 속성 */
  sx?: LhSxProps
}
LhCascaderItemConfig (@lh-ui/share/core/cascader에서 가져옴)
ts
/**
 * Cascader props의 item 속성 매핑
 */
export interface LhCascaderItemConfig {
  value?: string
  label?: string
  children?: string
  disabled?: string
  leaf?: string
}
LhCascaderNode (@lh-ui/share/core/cascader에서 가져옴)
ts
/**
 * Cascader 노드
 */
export interface LhCascaderNode {
  value: string | number
  label: string
  disabled?: boolean
  leaf?: boolean
  children?: LhCascaderNode[]
}
LhComponentSize (@lh-ui/share/core/shared에서 가져옴)
ts
export type LhComponentSize = (typeof LH_SIZE_CONST)[keyof typeof LH_SIZE_CONST]

Slots ​

슬롯설명기본 내용
no-match필터링 결과가 없을 때 검색 패널의 커스텀 내용언어 팩 cascader.noMatch(중국어 '无匹配数据')

국풍의 아름다움으로 코드의 토대를 세웁니다