Skip to content

Commit 4a2fdc9

Browse files
authored
Merge pull request #102 from wsfe/feat/update-node-api
feat: add update node APIs
2 parents 8c45198 + 77c7a2c commit 4a2fdc9

File tree

12 files changed

+548
-90
lines changed

12 files changed

+548
-90
lines changed
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<template>
2+
<button @click="handleClearChildren">Clear node-1 children</button>
3+
<button @click="handleSetChildren">Set node-1 children</button>
4+
<button @click="handleUpdateChildren">Update node-1 children</button>
5+
<div :style="{ height: '300px' }">
6+
<VTree ref="tree" checkable selectable />
7+
</div>
8+
</template>
9+
10+
<script setup lang="ts">
11+
import { computed, onMounted, ref } from 'vue'
12+
import VTree from '@wsfe/vue-tree'
13+
14+
const tree = ref()
15+
16+
const children = Array.from({ length: 100000 }).map((_, i) => {
17+
return {
18+
title: `node-1-${i + 1}`,
19+
id: `node-1-${i + 1}`,
20+
}
21+
})
22+
23+
const data = [
24+
{
25+
title: 'node-1',
26+
id: 'node-1',
27+
children,
28+
},
29+
{
30+
title: 'node-2',
31+
id: 'node-2',
32+
children: [
33+
{
34+
title: 'node-2-1',
35+
id: 'node-2-1',
36+
},
37+
],
38+
},
39+
]
40+
41+
onMounted(() => {
42+
tree.value.setData(data)
43+
})
44+
45+
const handleSetChildren = () => {
46+
tree.value.updateNode('node-1', { children })
47+
}
48+
const handleClearChildren = () => {
49+
tree.value.updateNode('node-1', { children: [] })
50+
}
51+
const handleUpdateChildren = () => {
52+
tree.value.updateNode('node-1', {
53+
children: children.map((child) => {
54+
return {
55+
...child,
56+
title: `${child.title} ${Date.now()}`,
57+
checked: true,
58+
}
59+
})
60+
})
61+
}
62+
</script>
63+
64+
<style scoped>
65+
button {
66+
border: 1px solid lightgray;
67+
border-radius: 8px;
68+
padding-left: 10px;
69+
padding-right: 10px;
70+
margin-right: 20px;
71+
}
72+
</style>
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<template>
2+
<button @click="handleUpdateCount">Update node-1 count</button>
3+
<VTree ref="tree">
4+
<template #node="{ node }">
5+
<span>{{ node.title }}</span>
6+
<span v-if="typeof node.count === 'number'">
7+
Count: {{ node.count }}
8+
</span>
9+
</template>
10+
</VTree>
11+
</template>
12+
13+
<script setup lang="ts">
14+
import { onMounted, ref } from 'vue'
15+
import VTree from '@wsfe/vue-tree'
16+
17+
const tree = ref()
18+
19+
const data = [
20+
{
21+
title: 'node-1',
22+
id: 'node-1',
23+
count: 0,
24+
children: [
25+
{
26+
title: 'node-1-1',
27+
id: 'node-1-1',
28+
},
29+
{
30+
title: 'node-1-2',
31+
id: 'node-1-2',
32+
},
33+
],
34+
},
35+
{
36+
title: 'node-2',
37+
id: 'node-2',
38+
children: [
39+
{
40+
title: 'node-2-1',
41+
id: 'node-2-1',
42+
},
43+
],
44+
},
45+
]
46+
47+
onMounted(() => {
48+
tree.value.setData(data)
49+
})
50+
51+
const handleUpdateCount = () => {
52+
const key = 'node-1'
53+
const currentCount = tree.value.getNode(key).count
54+
tree.value.updateNode(key, { count: currentCount + 1 })
55+
}
56+
</script>
57+
58+
<style scoped>
59+
button {
60+
border: 1px solid lightgray;
61+
border-radius: 8px;
62+
padding-left: 10px;
63+
padding-right: 10px;
64+
margin-right: 20px;
65+
}
66+
</style>
+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<template>
2+
<button @click="handleUpdateSingleNode">Update node-1</button>
3+
<button @click="handleUpdateMultipleNode">Update node-1 & node-2</button>
4+
<VTree ref="tree" />
5+
</template>
6+
7+
<script setup lang="ts">
8+
import { computed, onMounted, ref } from 'vue'
9+
import VTree from '@wsfe/vue-tree'
10+
11+
const tree = ref()
12+
13+
const data = [
14+
{
15+
title: 'node-1',
16+
id: 'node-1',
17+
children: [
18+
{
19+
title: 'node-1-1',
20+
id: 'node-1-1',
21+
},
22+
{
23+
title: 'node-1-2',
24+
id: 'node-1-2',
25+
},
26+
],
27+
},
28+
{
29+
title: 'node-2',
30+
id: 'node-2',
31+
children: [
32+
{
33+
title: 'node-2-1',
34+
id: 'node-2-1',
35+
},
36+
],
37+
},
38+
]
39+
40+
onMounted(() => {
41+
tree.value.setData(data)
42+
})
43+
44+
const count = ref(0)
45+
46+
const handleUpdateSingleNode = () => {
47+
count.value++
48+
tree.value.updateNode('node-1', { title: `node-1 - ${count.value}` })
49+
}
50+
const handleUpdateMultipleNode = () => {
51+
count.value++
52+
tree.value.updateNodes([
53+
{
54+
id: 'node-1',
55+
title: `node-1 - ${count.value}`,
56+
},
57+
{
58+
id: 'node-2',
59+
title: `node-2 - ${count.value}`,
60+
},
61+
])
62+
}
63+
</script>
64+
65+
<style scoped>
66+
button {
67+
border: 1px solid lightgray;
68+
border-radius: 8px;
69+
padding-left: 10px;
70+
padding-right: 10px;
71+
margin-right: 20px;
72+
}
73+
</style>

site/api/vtree.md

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@
9797
| filter | 过滤节点 | `keyword: string`: 过滤关键词<br/>`filterMethod: (keyword: string, node: TreeNode) => boolean`: 过滤方法,默认为 filterMethod Prop ,如果没有传 filterMethod Prop 则为搜索 title 字段的一个内置方法 | `void` |
9898
| showCheckedNodes | 展示已选节点 | `showUnloadCheckedNodes: boolean`: 是否显示未加载的选中节点,默认为 Prop 传入的值 | `void` |
9999
| loadRootNodes | 从远程加载根节点 || `Promise<void>` |
100+
| updateNode `4.1.0` | 更新单个节点 | `key: string \| number`: 节点 key<br/>`newNode: object`: 新节点数据,某些字段将被忽略,例如以下划线 "_" 开头的字段,以及 key 字段和 `indeterminate`, `visible`, `isLeaf`| `void` |
101+
| updateNodes `4.1.0` | 更新多个节点 | `newNodes: object[]`: 新节点数据数组,与 `updateNode` 相同,特定的字段会被忽略,且没有 key 字段的元素将被忽略 | `void` |
100102
| scrollTo | 滚动到指定节点位置 | `key: string \| number`: 节点 key<br/>`verticalPosition: 'top' \| 'center' \| 'bottom' \| number`: 滚动的垂直位置 | `void` |
101103

102104
## VTree Slots

site/en/api/vtree.md

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ Note: Since `2.0.8`, the node info returned in events contains the full node inf
9797
| filter | Filter nodes | `keyword: string`: filter keyword<br/>`filterMethod: (keyword: string, node: TreeNode) => boolean`: filter method, default to filterMethod prop. if filterMethod prop is not present, it's an internal method that searches node title | `void` |
9898
| showCheckedNodes | Show checked nodes | `showUnloadCheckedNodes: boolean`: whether to show checked nodes that are not loaded, default to prop value | `void` |
9999
| loadRootNodes | Load root nodes from remote | None | `Promise<void>` |
100+
| updateNode `4.1.0` | Update single node | `key: string \| number`: node key<br/>`newNode: object`: new node data, some fields will be ignored, like those start with underscore '_', the key field and `indeterminate`, `visible`, `isLeaf`, etc. | `void` |
101+
| updateNodes `4.1.0` | Update multiple nodes | `newNodes: object[]`: new nodes array, some specific fields will be ignored like `updateNode`, and the elements without key field also will be ignored | `void` |
100102
| scrollTo | Scroll to specific node position | `key: string \| number`: node key<br/>`verticalPosition: 'top' \| 'center' \| 'bottom' \| number`: vertical position of scrolling | `void` |
101103

102104
## VTree Slots

site/en/examples/node-manipulation.md

+20
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,23 @@ Enable `draggable` and `droppable`
2222
- Invoke `remove` to remove a node
2323

2424
<CodeDemo component="NodeCreationAndRemoval" />
25+
26+
## Update Node Title {#update-node-title}
27+
28+
Invoke `updateNode` method to update some fields of tree node
29+
30+
Invoke `updateNodes` to update multiple nodes
31+
32+
<CodeDemo component="UpdateNodeTitle" />
33+
34+
## Update Custom Field {#update-custom-field}
35+
36+
Invoke `updateNode` method to update custom fields in tree node
37+
38+
<CodeDemo component="UpdateCustomField" />
39+
40+
## Reload Child Nodes {#reload-children}
41+
42+
Invoke `updateNode` and pass a new `children` list to reload child nodes
43+
44+
<CodeDemo component="ReloadChildren" />

site/examples/node-manipulation.md

+20
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,23 @@
2222
- 调用树组件的 `remove` 方法,可移除节点
2323

2424
<CodeDemo component="NodeCreationAndRemoval" />
25+
26+
## 更新节点名称 {#update-node-title}
27+
28+
调用树组件的 `updateNode` 方法可更新节点部分字段
29+
30+
调用 `updateNodes` 可批量更新
31+
32+
<CodeDemo component="UpdateNodeTitle" />
33+
34+
## 更新自定义字段 {#update-custom-field}
35+
36+
调用树组件的 `updateNode` 方法更新自定义字段
37+
38+
<CodeDemo component="UpdateCustomField" />
39+
40+
## 重新加载子节点 {#reload-children}
41+
42+
调用 `updateNode` 传入新的 `children` 列表可以重新加载子节点
43+
44+
<CodeDemo component="ReloadChildren" />

src/components/Tree.vue

+4
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ const {
405405
filter,
406406
showCheckedNodes,
407407
loadRootNodes,
408+
updateNode,
409+
updateNodes,
408410
} = usePublicTreeAPI(nonReactive, props, {
409411
resetSpaceHeights,
410412
updateExpandedKeys,
@@ -705,6 +707,8 @@ defineExpose({
705707
filter,
706708
showCheckedNodes,
707709
loadRootNodes,
710+
updateNode,
711+
updateNodes,
708712
scrollTo,
709713
})
710714

src/constants/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export const TREE_API_METHODS = [
3939
'filter',
4040
'showCheckedNodes',
4141
'loadRootNodes',
42+
'updateNode',
43+
'updateNodes',
4244
'scrollTo'
4345
] as const
4446

src/hooks/usePublicTreeAPI.ts

+14
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,18 @@ export const usePublicTreeAPI = (
235235
isRootLoading.value = false
236236
})
237237
}
238+
/**
239+
* 更新单个节点
240+
*/
241+
function updateNode(key: TreeNodeKeyType, newNode: ITreeNodeOptions) {
242+
return nonReactive.store.updateNode(key, newNode)
243+
}
244+
/**
245+
* 更新多个节点
246+
*/
247+
function updateNodes(newNodes: ITreeNodeOptions[]) {
248+
return nonReactive.store.updateNodes(newNodes)
249+
}
238250

239251
return {
240252
unloadCheckedNodes,
@@ -269,5 +281,7 @@ export const usePublicTreeAPI = (
269281
filter,
270282
showCheckedNodes,
271283
loadRootNodes,
284+
updateNode,
285+
updateNodes,
272286
}
273287
}

0 commit comments

Comments
 (0)