Skip to content

TreeSelector

성능을 고려하여 가상 스크롤이 적용된 다목적 트리 컴포넌트입니다.

개요

TreeSelector는 계층적 데이터를 트리 구조로 표시하며, 단일 선택과 다중 선택 모드를 지원합니다. 가상 스크롤링을 통해 대용량 데이터도 효율적으로 처리할 수 있습니다.

Props 인터페이스

typescript
interface Props<T = any> {
    tree: TreeNode<T>[]; // 트리 데이터
    multiSelect?: boolean; // 다중 선택 모드 (기본값: false)
    leafIconForMultiSelect?: IconTypes; // 다중 선택 시 체크박스 표시할 아이콘 타입
    width?: number; // 컴포넌트 너비 (기본값: 0 - 자동)
    height?: number; // 컴포넌트 높이 (기본값: 300)
    checkedKeys?: string[]; // 체크된 노드 키 목록 (기본값: [])
}

interface TreeNode<T = any> {
    key: string; // 고유 키
    label: string; // 표시 텍스트
    children: TreeNode<T>[]; // 자식 노드들
    fold?: boolean; // 접힘 상태 (기본값: false)
    check?: boolean; // 체크 상태 (기본값: false)
    disable?: boolean; // 비활성화 상태 (기본값: false)
    icon?: IconTypes; // 노드 아이콘
    data?: T; // 사용자 데이터
}

이벤트

  • fold: 노드 접힘/펼침 시 발생 - (nodes: TreeNode<T>[]) => void
  • change: 노드 선택 변경 시 발생 - (nodes: TreeNode<T>[]) => void

기본 사용법

vue
<template>
    <TreeSelector
        :tree="treeData"
        :multi-select="false"
        :width="300"
        :height="400"
        @change="onSelectionChange"
        @fold="onNodeFold"
    />
</template>

<script setup lang="ts">
import { TreeSelector, type TreeNode } from '@jennifersoft/apm-components';
import { ICON_TYPE } from '@jennifersoft/vue-components-v2';

interface CustomData {
    id: number;
    name: string;
}

const treeData: TreeNode<CustomData>[] = [
    {
        key: '1',
        label: 'Root Node',
        icon: ICON_TYPE.folder,
        data: { id: 1, name: 'root' },
        children: [
            {
                key: '1-1',
                label: 'Child Node',
                icon: ICON_TYPE.file,
                data: { id: 2, name: 'child' },
                children: [],
            },
        ],
    },
];

const onSelectionChange = (nodes: TreeNode<CustomData>[]) => {
    console.log('Selected nodes:', nodes);
};

const onNodeFold = (nodes: TreeNode<CustomData>[]) => {
    console.log('Fold state changed:', nodes);
};
</script>

인터랙티브 데모

TreeSelector

사용 시나리오

1. 단일 선택 모드 (Single Selection)

단일 노드만 선택할 수 있는 기본 모드입니다.

vue
<template>
    <TreeSelector
        :tree="treeData"
        :multi-select="false"
        @change="onSingleSelect"
    />
</template>

<script setup>
const onSingleSelect = (nodes) => {
    const selectedNode = nodes[0]; // 항상 하나의 노드만 선택됨
    console.log('Selected:', selectedNode.label);
};
</script>

2. 다중 선택 모드 (Multi Selection)

여러 노드를 동시에 선택할 수 있습니다.

vue
<template>
    <TreeSelector
        :tree="treeData"
        :multi-select="true"
        @change="onMultiSelect"
    />
</template>

<script setup>
const onMultiSelect = (nodes) => {
    console.log('Selected nodes count:', nodes.length);
    nodes.forEach((node) => {
        console.log('Selected:', node.label);
    });
};
</script>

3. 제한된 다중 선택 (Leaf-only Multi Selection)

특정 아이콘을 가진 노드(주로 리프 노드)만 체크박스를 표시합니다.

vue
<template>
    <TreeSelector
        :tree="domainTreeData"
        :multi-select="true"
        :leaf-icon-for-multi-select="ICON_TYPE.domain"
        @change="onDomainSelect"
    />
</template>

<script setup>
import { ICON_TYPE } from '@jennifersoft/vue-components-v2';

// domain 아이콘을 가진 노드만 선택 가능
const onDomainSelect = (nodes) => {
    const domainIds = nodes.map((node) => node.data.domainId);
    console.log('Selected domains:', domainIds);
};
</script>

4. 미리 체크된 상태로 시작

vue
<template>
    <TreeSelector
        :tree="treeData"
        :multi-select="true"
        :checked-keys="['node-1', 'node-3']"
        @change="onPreCheckedChange"
    />
</template>

고급 기능

가상 스크롤링

대용량 트리 데이터의 성능을 위해 가상 스크롤링이 자동으로 적용됩니다.

vue
<template>
    <!-- 수천 개의 노드도 부드럽게 렌더링 -->
    <TreeSelector :tree="massiveTreeData" :height="400" />
</template>

커스텀 아이콘 사용

각 노드에 다양한 아이콘을 설정할 수 있습니다.

vue
<script setup>
import { ICON_TYPE } from '@jennifersoft/vue-components-v2';

const customTreeData = [
    {
        key: '1',
        label: 'Server Group',
        icon: ICON_TYPE.domainGroup,
        children: [
            {
                key: '1-1',
                label: 'Web Server',
                icon: ICON_TYPE.domain,
                children: [],
            },
            {
                key: '1-2',
                label: 'Database Server',
                icon: ICON_TYPE.database,
                children: [],
            },
        ],
    },
];
</script>

노드 상태 관리

vue
<script setup>
const treeDataWithStates = [
    {
        key: '1',
        label: 'Active Node',
        disable: false, // 활성화됨
        fold: false, // 펼쳐짐
        check: true, // 체크됨
        children: [
            {
                key: '1-1',
                label: 'Disabled Node',
                disable: true, // 비활성화됨
                children: [],
            },
        ],
    },
];
</script>

데이터 구조 예제

도메인/인스턴스 트리

typescript
interface DomainData {
    domainId: number;
    instanceId: number;
}

const domainTree: TreeNode<DomainData>[] = [
    {
        key: 'domain-1000',
        label: 'Production',
        icon: ICON_TYPE.domainGroup,
        data: { domainId: 1000, instanceId: 0 },
        children: [
            {
                key: 'instance-1001',
                label: 'web-server-01',
                icon: ICON_TYPE.domain,
                data: { domainId: 1000, instanceId: 1001 },
                children: [],
            },
        ],
    },
];

성능 최적화

  1. 가상 스크롤링: 대용량 데이터 처리
  2. 지연 로딩: 필요한 노드만 렌더링
  3. 메모리 효율성: 불필요한 DOM 노드 최소화

접근성 (Accessibility)

  • 키보드 네비게이션 지원
  • 스크린 리더 호환성
  • ARIA 속성 자동 적용

의존성

  • Vue 3 Composition API
  • @jennifersoft/vue-components-v2 (아이콘)
  • Virtual Scrolling 라이브러리 (내장)