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 라이브러리 (내장)