Tree 트리
폴더나 조직도처럼 중첩된 계층 구조를 트리 형태로 보여 주는 컴포넌트예요.
출처: 문서
본문
언제 사용하나요?
폴더, 조직도, 생물 분류, 국가·지역 등 세상 대부분의 구조는 트리 구조예요. Tree 컴포넌트를 사용하면 이런 계층 관계를 온전하게 표현할 수 있고, 펼치기/접기, 선택 같은 인터랙션 기능도 제공해요.
기본 사용법
:::demo 중첩된 트리 구조 표현, 연결선, 펼치기/접기, 클릭 선택 기능을 보여 줘요. 애니메이션 효과는 트리 노드 높이에 영향을 받고 기본 높이는 30px이에요. 트리 노드를 커스텀할 때는 애니메이션이 정상적으로 표시되도록 노드 높이를 직접 설정하는 편이 좋아요.
<template>
<d-tree :data="data"></d-tree>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const data = ref([
{
label: 'Parent node 1',
children: [
{
label: 'Parent node 1-1',
children: [{ label: 'Leaf node 1-1-1' }],
},
{ label: 'Leaf node 1-2' },
],
},
{ label: 'Leaf node 2' },
]);
return {
data,
};
},
});
</script>
:::
노드 지연 로딩
:::demo 해당 노드의 isLeaf 파라미터를 false로 설정하고, 컴포넌트가 lazyLoad 메서드를 콜백하도록 해서 노드 지연 로딩을 구현해요.
<template>
<d-tree :data="data" @lazy-load="lazyLoad"></d-tree>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const data = ref([
{
label: 'Parent node 1',
children: [
{
label: 'Parent node 1-1 - dynamic loading',
isLeaf: false,
},
{ label: 'Leaf node 1-2' },
],
},
{ label: 'Leaf node 2 - dynamic loading', isLeaf: false },
]);
const lazyLoad = (node, callback) => {
setTimeout(() => {
const data = [
{
label: 'child node 1',
expanded: true,
children: [
{
label: 'child node 1-1',
},
{
label: 'child node 1-2',
},
],
},
{
label: 'child node 2',
children: [
{
label: 'child node 2-1',
},
],
},
];
callback({
treeItems: data,
node,
});
}, 500);
};
return {
data,
lazyLoad,
};
},
});
</script>
:::
체크 기능
:::demo check로 체크 기능을 켤 수 있어요.
<template>
<div class="flex flex-row" style="height: 28px;">
<label class="flex items-center mr-xl"><span class="inline-block mr-xs">开启勾选</span><d-switch v-model="openCheck"></d-switch></label>
<d-radio-group v-if="openCheck" v-model="currentStrategy" direction="row">
<d-radio v-for="strategy of checkStrategy" :key="strategy" :value="strategy">{{ strategy }}</d-radio>
</d-radio-group>
</div>
<d-tree
:data="data"
:check="currentStrategy"
@toggle-change="toggleChange"
@check-change="checkChange"
@select-change="selectChange"
@node-click="nodeClick"
></d-tree>
</template>
<script>
import { defineComponent, ref, watch } from 'vue';
export default defineComponent({
setup() {
const openCheck = ref(true);
const checkStrategy = ref(['both', 'downward', 'upward', 'none']);
const currentStrategy = ref('both');
const data = ref([
{
label: 'Parent node 1',
children: [
{
label: 'Parent node 1-1',
children: [{ label: 'Leaf node 1-1-1' }, { label: 'Leaf node 1-1-2' }],
},
{ label: 'Leaf node 1-2' },
],
},
{ label: 'Leaf node 2' },
]);
watch(openCheck, (newVal) => {
if (newVal === false) {
currentStrategy.value = false;
} else {
currentStrategy.value = 'both';
data.value = [
{
label: 'Parent node 1',
children: [
{
label: 'Parent node 1-1',
children: [{ label: 'Leaf node 1-1-1' }, { label: 'Leaf node 1-1-2' }],
},
{ label: 'Leaf node 1-2' },
],
},
{ label: 'Leaf node 2' },
];
}
});
const toggleChange = (node) => {
console.log('toggleChange node:', node);
};
const checkChange = (node) => {
console.log('checkChange node:', node);
};
const selectChange = (node) => {
console.log('selectChange node:', node);
};
const nodeClick = (node) => {
console.log('nodeClick node:', node);
};
return {
data,
openCheck,
checkStrategy,
currentStrategy,
toggleChange,
checkChange,
selectChange,
nodeClick,
};
},
});
</script>
:::
기본 상태
:::demo expanded/selected/checked로 각각 기본 펼치기/접기 상태, 클릭 선택, 체크 상태를 설정해요.
<template>
<d-tree :data="data" check></d-tree>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const data = ref([
{
label: 'Parent node 1',
expanded: true,
children: [
{
label: 'Parent node 1-1',
children: [{ label: 'Leaf node 1-1-1' }],
},
{
label: 'Leaf node 1-2',
checked: true,
},
],
},
{
label: 'Leaf node 2',
selected: true,
},
]);
return {
data,
};
},
});
</script>
:::
비활성 상태
:::demo disableToggle/disableSelect/disableCheck로 각각 펼치기/접기, 클릭 선택, 체크를 비활성화해요.
<template>
<d-tree :data="data" check></d-tree>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const data = ref([
{
label: 'Parent node 1',
expanded: true,
children: [
{
label: 'Parent node 1-1',
disableToggle: true,
disableSelect: true,
disableCheck: true,
children: [{ label: 'Leaf node 1-1-1' }],
},
{
label: 'Leaf node 1-2',
disableCheck: true,
},
],
},
{
label: 'Leaf node 2',
disableSelect: true,
},
]);
return {
data,
};
},
});
</script>
:::
커스텀 아이콘
:::demo content 슬롯으로 노드 내용을 커스텀할 수 있어요. 예를 들어 노드 내용 앞에 아이콘을 추가할 수 있어요. icon 슬롯으로는 펼치기/접기 아이콘을 커스텀할 수 있어요.
<template>
<d-tree :data="data">
<template #content="{ nodeData }">
<svg style="margin-right: 8px" viewBox="0 0 16 16" width="16" height="16">
<path
:d="`${
nodeData.isLeaf
? 'M13,6 L9,6 L9,5 L9,2 L3,2 L3,14 L13,14 L13,6 Z M12.5857864,5 L10,2.41421356 L10,5 L12.5857864,5 Z M2,1 L10,1 L14,5 L14,15 L2,15 L2,1 Z'
: nodeData.expanded
? 'M16,6 L14,14 L2,14 L0,6 L16,6 Z M14.7192236,7 L1.28077641,7 L2.78077641,13 L13.2192236,13 L14.7192236,7 Z M6,1 L8,3 L15,3 L15,5 L14,5 L14,4 L7.58578644,4 L5.58578644,2 L2,2 L2,5 L1,5 L1,1 L6,1 Z'
: 'M14,6 L14,5 L7.58578644,5 L5.58578644,3 L2,3 L2,6 L14,6 Z M14,7 L2,7 L2,13 L14,13 L14,7 Z M1,2 L6,2 L8,4 L15,4 L15,14 L1,14 L1,2 Z'
}`"
stroke-width="1"
fill="#8a8e99"
></path>
</svg>
{{ nodeData.label }}
</template>
<template #icon="{ nodeData, toggleNode }">
<span v-if="nodeData.isLeaf" class="devui-tree-node__indent"></span>
<span
v-else
@click="
(event) => {
event.stopPropagation();
toggleNode(nodeData);
}
"
>
<svg
:style="{ transform: nodeData.expanded ? 'rotate(90deg)' : '', marginLeft: '-2.5px', marginRight: '14.5px', cursor: 'pointer' }"
viewBox="0 0 1024 1024"
width="12"
height="12"
>
<path d="M204.58705 951.162088 204.58705 72.836889 819.41295 511.998977Z" fill="#8a8e99"></path>
</svg>
</span>
</template>
</d-tree>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const data = ref([
{
label: 'Parent node 1',
children: [
{
label: 'Parent node 1-1',
children: [{ label: 'Leaf node 1-1-1' }],
},
{ label: 'Leaf node 1-2' },
],
},
{ label: 'Leaf node 2' },
]);
return {
data,
};
},
});
</script>
:::
노드 병합
:::demo
<template>
<d-tree :data="data" ref="treeRef"></d-tree>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue';
export default defineComponent({
setup() {
const treeRef = ref(null);
const data = ref([
{
label: 'Parent node 1',
children: [
{
label: 'Parent node 1-1',
children: [
{
label: 'Parent node 1-1-1',
children: [
{
label: 'Parent node 1-1-1-1',
},
],
},
],
},
],
},
{
label: 'Parent node 2',
children: [
{
label: 'Parent node 2-1',
children: [
{
label: 'Leaf node 2-1-1',
},
{
label: 'Leaf node 2-1-2',
},
],
},
],
},
{
label: 'Parent node 3',
children: [
{
label: 'Leaf node 3-1',
children: [
{
label: 'Leaf node 3-1-1',
children: [
{
label: 'Leaf node 3-1-1-1',
},
],
},
],
},
{
label: 'Leaf node 3-2',
},
],
},
]);
onMounted(() => {
treeRef.value.treeFactory.mergeTreeNodes();
treeRef.value.treeFactory.expandAllNodes();
});
return {
data,
treeRef,
};
},
});
</script>
:::
조작 버튼
:::demo 외부 조작 버튼과 호버 버튼을 정의할 수 있어요.
<template>
<d-tree :data="data" ref="treeRef" operate @select-change="selectChange"></d-tree>
<d-button variant="solid" size="sm" @click="addNode">Add</d-button>
<d-button size="sm" class="ml-xs" @click="deleteNode">Delete</d-button>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const treeRef = ref();
const selectedNode = ref();
const data = ref([
{
label: 'Parent node 1',
id: 'node-1',
children: [
{
label: 'Leaf node 1-1',
id: 'node-1-1',
children: [{ label: 'Leaf node 1-1-1', id: 'node-1-1-1' }],
},
{ label: 'Leaf node 1-2', id: 'node-1-2' },
],
},
{ label: 'Parent node 2', id: 'node-2' },
]);
const addNode = () => {
if (!selectedNode.value) {
return;
}
const childs = treeRef.value.treeFactory.getChildren(selectedNode.value);
let labelName = 'new node';
if (!childs || childs.length === 0) {
labelName = selectedNode.value.label + '-1';
} else if (childs.length > 0) {
labelName = selectedNode.value.label + `-${childs.length + 1}`;
}
if (labelName.startsWith('Parent')) {
labelName = labelName.replace('Parent', 'Leaf');
}
treeRef.value.treeFactory.insertBefore(selectedNode.value, { label: labelName });
};
const deleteNode = () => {
if (!selectedNode.value) {
return;
}
treeRef.value.treeFactory.removeNode(selectedNode.value);
};
const selectChange = (selected) => {
selectedNode.value = selected;
};
return {
treeRef,
data,
addNode,
deleteNode,
selectChange,
};
},
});
</script>
:::
검색과 필터
:::demo treeFactory의 searchTree 메서드로 노드를 검색하거나 필터링할 수 있어요.
<template>
<d-search class="mb10" style="width: 300px" is-keyup-search placeholder="search your node..." :delay="1000" @search="onSearch"></d-search>
<d-search
class="mb10"
style="width: 300px"
is-keyup-search
placeholder="filter your node..."
:delay="1000"
@search="onSearch1"
></d-search>
<d-row class="mb10" align="middle">
<d-search
style="width: 300px"
is-keyup-search
placeholder="filter your node by custom key..."
:delay="1000"
@search="onSearch2"
></d-search>
<span class="ml8">
<d-tooltip position="top" content="使用自定义的属性搜索匹配树节点">
<d-icon name="help" />
</d-tooltip>
</span>
</d-row>
<d-row class="mb10" align="middle">
<d-search style="width: 300px" is-keyup-search placeholder="filter your node by Regex..." :delay="1000" @search="onSearch3"></d-search>
<span class="ml8">
<d-tooltip position="top" content="使用正则表达式限定搜索范围">
<d-icon name="help" />
</d-tooltip>
</span>
</d-row>
<d-tree ref="treeRef" :data="data"></d-tree>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const treeRef = ref();
const data = ref([
{
label: 'parent node 1',
customSearchValue: 'a',
},
{
label: 'parent node 2',
customSearchValue: 'b',
children: [
{
label: 'child node 2-1',
customSearchValue: 'c',
children: [
{
label: 'child node 2-1-1',
customSearchValue: 'd',
},
{
label: 'child node 2-1-2',
customSearchValue: 'e',
},
],
},
{
label: 'child node 2-2',
customSearchValue: 'f',
children: [
{
label: 'child node 2-2-1',
customSearchValue: 'g',
},
{
label: 'child node 2-2-2',
customSearchValue: 'h',
},
],
},
],
},
{
label: 'parent node 3',
customSearchValue: 'i',
children: [
{
label: 'child node 3-1',
customSearchValue: 'j',
},
{
label: 'child node 3-2',
customSearchValue: 'k',
},
],
},
{
label: 'parent node 4',
customSearchValue: 'l',
children: [
{
label: 'child node 4-1',
customSearchValue: 'm',
},
{
label: 'child node 4-2',
customSearchValue: 'n',
},
],
},
{
label: 'parent node 5',
customSearchValue: 'o',
children: [
{
label: 'child node 5-1',
customSearchValue: 'p',
},
{
label: 'child node 5-2',
customSearchValue: 'q',
},
],
},
]);
const onSearch = (value) => {
treeRef.value.treeFactory.searchTree(value, { isFilter: false });
};
const onSearch1 = (value) => {
treeRef.value.treeFactory.searchTree(value, { isFilter: true });
};
const onSearch2 = (value) => {
treeRef.value.treeFactory.searchTree(value, { isFilter: true, matchKey: 'customSearchValue' });
};
const onSearch3 = (value) => {
const regex = new RegExp('^' + value + '[\s\S]*');
treeRef.value.treeFactory.searchTree(value, { isFilter: true, pattern: regex });
};
return {
treeRef,
data,
onSearch,
onSearch1,
onSearch2,
onSearch3,
};
},
});
</script>
<style>
.mb10 {
margin-bottom: 10px;
}
.ml8 {
margin-left: 8px;
}
</style>
:::
가상 스크롤
:::demo 가상 스크롤로 대용량 데이터 로딩 문제를 처리해요.
<template>
<d-search class="mb10" style="width: 300px" is-keyup-search placeholder="search your node..." :delay="1000" @search="onSearch"></d-search>
<d-search
class="mb10"
style="width: 300px"
is-keyup-search
placeholder="filter your node..."
:delay="1000"
@search="onSearch1"
></d-search>
<d-tree :data="data" :height="300" ref="treeRef"></d-tree>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue';
export default defineComponent({
setup() {
const treeRef = ref(null);
const data = ref([
...Array.from({ length: 100 }).map((_, index) => ({
label: 'Parent node ' + index,
children:
index % 2 === 0
? Array.from({ length: 10 }).map((_, index2) => ({
label: 'Leaf node ' + index + '-' + index2,
}))
: undefined,
})),
]);
onMounted(() => {
treeRef.value.treeFactory.expandAllNodes();
});
const onSearch = (value) => {
treeRef.value.treeFactory.searchTree(value, { isFilter: false });
};
const onSearch1 = (value) => {
treeRef.value.treeFactory.searchTree(value, { isFilter: true });
};
return {
data,
treeRef,
onSearch,
onSearch1,
};
},
});
</script>
:::
드래그 앤 드롭 트리
:::demo OperableTree의 dragdrop 속성으로 노드 드래그 기능을 설정하고, 외부 요소를 트리 안으로 드래그하는 것도 지원해요.
<template>
<div class="mb-0">Default</div>
<d-tree class="mb-2" :data="data" dragdrop></d-tree>
<div class="mb-0">Sortable</div>
<d-tree class="mb-2" :data="data" :dragdrop="{ dropPrev: true, dropNext: true, dropInner: true }"></d-tree>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const data = ref([
{
label: 'parent node 1',
},
{
label: 'parent node 2',
expanded: true,
children: [
{
label: 'leaf node 2-1',
expanded: true,
children: [
{
label: 'leaf node 2-1-1',
},
{
label: 'leaf node 2-1-2',
},
],
},
{
label: 'leaf node 2-2',
children: [
{
label: 'leaf node 2-2-1',
},
{
label: 'leaf node 2-2-2',
},
],
},
],
},
{
label: 'parent node 3',
expanded: true,
children: [
{
label: 'leaf node 3-1',
},
{
label: 'leaf node 3-2',
},
],
},
{
label: 'parent node 4',
expanded: true,
children: [
{
label: 'leaf node 4-1',
},
{
label: 'leaf node 4-2',
},
],
},
{
label: 'parent node 5',
expanded: true,
children: [
{
label: 'leaf node 5-1',
},
{
label: 'leaf node 5-2',
},
],
},
]);
return {
data,
};
},
});
</script>
:::
treeFactory 자주 쓰는 메서드
:::demo
<template>
<d-tree :data="data" ref="treeRef"></d-tree>
<d-button variant="solid" size="sm" @click="toggleNode">toggle parent node 1</d-button>
<d-button variant="solid" size="sm" class="ml-xs" @click="activeNode">active parent node 1</d-button>
<d-button variant="solid" size="sm" class="ml-xs" @click="addNode">add node for node 2</d-button>
<d-button size="sm" class="ml-xs" @click="deleteNode">delete node 3</d-button>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const treeRef = ref();
const data = ref([
{
label: 'Parent node 1',
id: 'node-1',
children: [
{
label: 'Leaf node 1-1',
id: 'node-1-1',
children: [{ label: 'Leaf node 1-1-1', id: 'node-1-1-1' }],
},
{ label: 'Leaf node 1-2', id: 'node-1-2' },
],
},
{ label: 'Node 2', id: 'node-2' },
{ label: 'Node 3', id: 'node-3' },
]);
const toggleNode = () => {
const treeData = treeRef.value.treeFactory.treeData.value;
let node;
treeData.forEach((item) => {
if (item.id === 'node-1') {
node = item;
}
});
treeRef.value.treeFactory.toggleNode(node);
};
const activeNode = () => {
const treeData = treeRef.value.treeFactory.treeData.value;
let node;
treeData.forEach((item) => {
if (item.id === 'node-1') {
node = item;
}
});
treeRef.value.treeFactory.toggleSelectNode(node);
};
const addNode = () => {
const treeData = treeRef.value.treeFactory.treeData.value;
let node;
treeData.forEach((item) => {
if (item.id === 'node-2') {
node = item;
}
});
treeRef.value.treeFactory.insertBefore(node, { label: 'new node' });
};
const deleteNode = () => {
const treeData = treeRef.value.treeFactory.treeData.value;
let node;
treeData.forEach((item) => {
if (item.id === 'node-3') {
node = item;
}
});
if (!node) {
return;
}
treeRef.value.treeFactory.removeNode(node);
};
return {
treeRef,
data,
toggleNode,
activeNode,
addNode,
deleteNode,
};
},
});
</script>
:::
Tree 파라미터
| 파라미터 | 타입 | 기본값 | 설명 | Demo 링크 |
|---|---|---|---|---|
| data | ITreeNode[] | [] |
선택, 트리 구조 데이터 | 기본 사용법 |
| check | ICheck | false |
선택, 체크 기능 사용 여부 | 체크 가능 |
| dragdrop | IDragdrop | false |
선택, 드래그 기능 사용 여부 | 드래그 가능 트리 |
Tree 이벤트
| 이벤트명 | 콜백 파라미터 | 설명 | Demo 링크 |
|---|---|---|---|
| toggle-change | Function(node) |
노드 펼침/접힘 콜백 이벤트. 선택된 노드 객체 반환 | 체크 가능 |
| check-change | Function(node) |
노드 체크 콜백 이벤트. 선택된 노드 객체 반환 | 체크 가능 |
| select-change | Function(node) |
노드 선택 콜백 이벤트. 선택된 노드 객체 반환 | 체크 가능 |
| node-click | Function(node) |
노드 클릭 이벤트. 클릭한 노드 객체 반환 | 체크 가능 |
| lazy-node | Function(node, callback) |
노드 지연 로딩 이벤트. 클릭한 노드 객체와 콜백 함수 반환 | 노드 지연 로딩 |
Tree 슬롯
| 슬롯명 | 설명 |
|---|---|
| default | 노드 커스텀 |
| content | 노드 콘텐츠 커스텀 |
| icon | 펼침/접기 버튼 커스텀 |
| loading | 노드 지연 로딩 시 loading 표시 콘텐츠 커스텀 |
TreeNode 파라미터
| 파라미터 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| data | ITreeNode | [] |
선택, 노드 데이터 |
| check | ICheck | false |
선택, 체크 기능 사용 여부 |
| dragdrop | IDragdrop | false |
선택, 드래그 기능 사용 여부 |
| height | number |
- |
선택, 가상 스크롤 사용 설정 |
Tree 타입 정의
ITreeNode
interface ITreeNode {
label: string;
id?: string;
children?: ITreeNode[];
selected?: boolean;
checked?: boolean;
expanded?: boolean;
disableSelect?: boolean;
disableCheck?: boolean;
disableToggle?: boolean;
}
ICheck
type ICheck = boolean | 'upward' | 'downward' | 'both' | 'none';
IDragdrop
type IDragdrop =
| boolean
| {
dropPrev?: boolean;
dropNext?: boolean;
dropInner?: boolean;
};
treeFactory
treeFactory는 컴포넌트 내부에서 노출하는 데이터와 메서드 모음으로, 트리 구조를 커스텀할 때 사용해요.
type TreeFactory = {
// 扁平化处理后的数据,IInnerTreeNode 见下表
treeData: Ref<IInnerTreeNode[]>;
// 获取节点层级
getLevel: (node: IInnerTreeNode) => number;
// 获取某个节点的子节点
getChildren: (
node: IInnerTreeNode,
config?: {
expanded?: boolean; // 是否只从展开了的节点中获取数据
recursive?: boolean; // 是否需要获取非直接子节点
}
) => IInnerTreeNode[];
// 获取某个节点的父节点
getParent: (node: IInnerTreeNode) => IInnerTreeNode;
// 获取当前是展开状态的节点
getExpendedTree: () => ComputedRef<IInnerTreeNode[]>;
// 获取某个节点在扁平化数据结构中的索引
getIndex: (node: IInnerTreeNode) => number;
// 设置某个节点的属性值
setNodeValue: (node: IInnerTreeNode, key: keyof IInnerTreeNode, value: valueof<IInnerTreeNode>) => void;
// 展开节点,并触发`toggle-change`事件
expandNode: (node: IInnerTreeNode) => void;
// 收起节点,并触发`toggle-change`事件
collapseNode: (node: IInnerTreeNode) => void;
// 展开/收起节点
toggleNode: (node: IInnerTreeNode) => void;
// 展开所有节点
expandAllNodes: () => void;
// 单选,并触发`select-change`事件
selectNode: (node: IInnerTreeNode) => void;
// 取消单选,并触发`select-change`事件
deselectNode: (node: IInnerTreeNode) => void;
// 单选/取消单选,并触发`select-change`事件
toggleSelectNode: (node: IInnerTreeNode) => void;
// 获取已单选的节点
getSelectedNode: () => IInnerTreeNode;
// 勾选,并触发`check-change`事件
checkNode: (node: IInnerTreeNode) => void;
// 取消勾选,并触发`check-change`事件
uncheckNode: (node: IInnerTreeNode) => void;
// 勾选/取消勾选,并触发`check-change`事件
toggleCheckNode: (node: IInnerTreeNode) => void;
// 获取已勾选的节点
getCheckedNodes: () => IInnerTreeNode[];
// 禁用节点单选
disableSelectNode: (node: IInnerTreeNode) => void;
// 禁用节点勾选
disableCheckNode: (node: IInnerTreeNode) => void;
// 禁用节点展开/收起
disableToggleNode: (node: IInnerTreeNode) => void;
// 启用节点单选
enableSelectNode: (node: IInnerTreeNode) => void;
// 启用节点勾选
enableCheckNode: (node: IInnerTreeNode) => void;
// 启用节点展开/收起
enableToggleNode: (node: IInnerTreeNode) => void;
// 当节点只有一个子节点时,合并显示
mergeTreeNodes: () => void;
// 懒加载某个节点的子节点
lazyLoadNodes: (node: IInnerTreeNode) => void;
// 搜索节点,参数为搜索关键字和搜索配置项,SearchFilterOption 见下表
searchTree: (target: string, option: SearchFilterOption) => void;
};
IInnerTreeNode
interface IInnerTreeNode extends ITreeNode {
level: number;
idType?: 'random';
parentId?: string;
isLeaf?: boolean;
parentChildNodeCount?: number;
currentIndex?: number;
loading?: boolean; // 节点是否显示加载中
childNodeCount?: number; // 该节点的子节点的数量
isMatched?: boolean; // 搜索过滤时是否匹配该节点
childrenMatched?: boolean; // 搜索过滤时是否有子节点存在匹配
isHide?: boolean; // 过滤后是否不显示该节点
matchedText?: string; // 节点匹配的文字(需要高亮显示)
}
SearchFilterOption
interface SearchFilterOption {
isFilter: boolean; // 是否是过滤节点
matchKey?: string; // node节点中匹配搜索过滤的字段名
pattern?: RegExp; // 搜索过滤时匹配的正则表达式
}
더 알아보기 (Learn more)
treeFactory가 제공하는 다양한 메서드를 활용하면 노드 추가·삭제·검색 같은 트리 조작을 자유롭게 확장할 수 있어요. 대용량 데이터를 다룰 때는 가상 스크롤 기능도 함께 살펴보세요.