Skip to content

Commit ba214e8

Browse files
committed
基本改造
1 parent de343fa commit ba214e8

File tree

4 files changed

+190
-37
lines changed

4 files changed

+190
-37
lines changed

src/components/VirtualTree/index.tsx

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
import {defineComponent, watch, ref, shallowRef, PropType, h} from 'vue';
22
import { cloneDeep } from 'lodash-es';
33
import {NodeKey, TreeNodeInstance, TreeNodeOptions, TypeWithNull, TypeWithUndefined} from "./types";
4-
import {
5-
checkedNodes,
6-
disabledKeys,
7-
expandedKeys,
8-
flattenTree,
9-
selectedNodes,
10-
updateDownwards,
11-
updateUpwards
12-
} from "./uses";
4+
135
import VirTreeNode from './node';
146
import VirtualList from '../VirtualList';
157
import './index.scss';
8+
import {TreeService} from "./service";
169

1710
export default defineComponent({
1811
name: 'VirTree',
@@ -25,10 +18,18 @@ export default defineComponent({
2518
type: Array as PropType<NodeKey[]>,
2619
default: () => []
2720
},
21+
defaultSelectedKey: {
22+
type: [String, Number],
23+
default: ''
24+
},
2825
defaultCheckedKeys: {
2926
type: Array as PropType<NodeKey[]>,
3027
default: () => []
3128
},
29+
defaultDisabledKeys: {
30+
type: Array as PropType<NodeKey[]>,
31+
default: () => []
32+
},
3233
showCheckbox: {
3334
type: Boolean,
3435
default: false
@@ -52,18 +53,22 @@ export default defineComponent({
5253
setup: function (props, {emit, slots, expose}) {
5354
const loading = shallowRef(false);
5455
const flatList = ref<Required<TreeNodeOptions>[]>([]);
56+
57+
const service = new TreeService();
58+
5559
watch(() => props.source, newVal => {
56-
flatList.value = flattenTree(newVal, props.defaultCheckedKeys, props.defaultExpandedKeys);
57-
console.log('expandedKeys>>', expandedKeys.value.selected);
60+
flatList.value = service.flattenTree(newVal, props.defaultSelectedKey, props.defaultCheckedKeys, props.defaultExpandedKeys, props.defaultDisabledKeys);
61+
// console.log('expandedKeys>>', expandedKeys.value.selected);
5862
}, {immediate: true});
5963
const selectChange = (node: Required<TreeNodeOptions>) => {
60-
const preSelectedNode = selectedNodes.value.selected[0];
64+
const preSelectedNode = service.selectedNodes.value.selected[0];
6165
let currentNode: TypeWithNull<TreeNodeOptions> = node;
62-
if (selectedNodes.value.isSelected(node)) {
63-
selectedNodes.value.clear();
66+
if (service.selectedNodes.value.isSelected(node)) {
67+
service.selectedNodes.value.clear();
6468
currentNode = null;
69+
service.defaultSelectedKey = '';
6570
} else {
66-
selectedNodes.value.select(node);
71+
service.selectedNodes.value.select(node);
6772
}
6873
emit('selectChange', {
6974
preSelectedNode,
@@ -73,27 +78,44 @@ export default defineComponent({
7378

7479

7580
const checkChange = ([checked, node]: [boolean, Required<TreeNodeOptions>]) => {
76-
checkedNodes.value.toggle(node);
81+
service.checkedNodes.value.toggle(node);
82+
if (!checked) {
83+
service.removeDefaultCheckedKeys(node);
84+
}
85+
7786
if (!props.checkStrictly) {
78-
updateDownwards(checked, node);
79-
updateUpwards(node, flatList.value);
87+
service.updateDownwards(checked, node);
88+
service.updateUpwards(node, flatList.value);
8089
}
8190
emit('checkChange', {checked, node});
8291
}
8392

8493
const expandNode = (node: Required<TreeNodeOptions>, children: TreeNodeOptions[] = []) => {
8594
const trueChildren = children.length ? children : cloneDeep(node.children)!;
86-
node.children = trueChildren.map(item => {
95+
node.children = (trueChildren as Required<TreeNodeOptions>[]).map(item => {
8796
item.loading = false;
8897
item.level = item.level || node.level! + 1;
8998
item.children = item.children || [];
9099
item.hasChildren = item.hasChildren || false;
91100
item.parentKey = node.nodeKey || null;
92-
if (props.defaultCheckedKeys.includes(item.nodeKey)) {
93-
checkedNodes.value.select(item as Required<TreeNodeOptions>);
101+
102+
if (props.defaultDisabledKeys.includes(item.nodeKey)) {
103+
service.disabledKeys.value.select(item.nodeKey);
104+
}
105+
106+
const selectedKey = service.selectedNodes.value.selected[0]?.nodeKey || service.defaultSelectedKey;
107+
if (selectedKey === item.nodeKey) {
108+
service.selectedNodes.value.select(item as Required<TreeNodeOptions>);
94109
}
95-
if (props.defaultExpandedKeys.includes(item.nodeKey)) {
96-
expandedKeys.value.select(item.nodeKey);
110+
111+
const allCheckedKeys = service.checkedNodes.value.selected.map(item => item.nodeKey).concat(service.defaultCheckedKeys);
112+
if (allCheckedKeys.includes(item.nodeKey) || (!props.checkStrictly && service.checkedNodes.value.isSelected(node))) {
113+
service.checkedNodes.value.select(item as Required<TreeNodeOptions>);
114+
}
115+
116+
const allExpandedKeys = service.expandedKeys.value.selected.concat(service.defaultExpandedKeys);
117+
if (allExpandedKeys.includes(item.nodeKey)) {
118+
service.expandedKeys.value.select(item.nodeKey);
97119
}
98120
return item;
99121
});
@@ -107,8 +129,9 @@ export default defineComponent({
107129
if (node.children?.length) {
108130
(node.children as Required<TreeNodeOptions>[]).forEach(item => {
109131
delKeys.push(item.nodeKey);
110-
if (expandedKeys.value.isSelected(item.nodeKey)) {
111-
expandedKeys.value.deselect(item.nodeKey);
132+
if (service.expandedKeys.value.isSelected(item.nodeKey)) {
133+
service.expandedKeys.value.deselect(item.nodeKey);
134+
service.removeDefaultExpandedKeys(item.nodeKey);
112135
recursion(item as Required<TreeNodeOptions>);
113136
}
114137
});
@@ -122,8 +145,8 @@ export default defineComponent({
122145

123146
const toggleExpand = (node: Required<TreeNodeOptions>) => {
124147
if (loading.value) return;
125-
expandedKeys.value.toggle(node.nodeKey);
126-
if (expandedKeys.value.isSelected(node.nodeKey)) {
148+
service.expandedKeys.value.toggle(node.nodeKey);
149+
if (service.expandedKeys.value.isSelected(node.nodeKey)) {
127150
if (node.children?.length) {
128151
expandNode(node);
129152
} else {
@@ -141,9 +164,10 @@ export default defineComponent({
141164
}
142165
}
143166
} else {
167+
service.removeDefaultExpandedKeys(node.nodeKey);
144168
collapseNode(node);
145169
}
146-
emit('toggleExpand', { status: expandedKeys.value.isSelected(node.nodeKey), node });
170+
emit('toggleExpand', { status: service.expandedKeys.value.isSelected(node.nodeKey), node });
147171
}
148172
const nodeRefs = ref<TreeNodeInstance[]>([]);
149173
const setRef = (index: number, node: any) => {
@@ -153,16 +177,16 @@ export default defineComponent({
153177
}
154178
expose({
155179
getSelectedNode: (): TypeWithUndefined<TreeNodeOptions> => {
156-
return selectedNodes.value.selected[0];
180+
return service.selectedNodes.value.selected[0];
157181
},
158182
getCheckedNodes: (): TreeNodeOptions[] => {
159-
return checkedNodes.value.selected;
183+
return service.checkedNodes.value.selected;
160184
},
161185
getHalfCheckedNodes: (): TreeNodeOptions[] => {
162186
return nodeRefs.value.filter(item => item.halfChecked()).map(item => item.rawNode);
163187
},
164188
getExpandedKeys: (): NodeKey[] => {
165-
return expandedKeys.value.selected;
189+
return service.expandedKeys.value.selected;
166190
}
167191
});
168192

@@ -181,10 +205,10 @@ export default defineComponent({
181205
default: (data: { item: Required<TreeNodeOptions>, index: number }) => h(VirTreeNode, {
182206
ref: setRef.bind(null, data.index),
183207
node: data.item,
184-
selectedNodes: selectedNodes.value,
185-
checkedNodes: checkedNodes.value,
186-
expandedKeys: expandedKeys.value,
187-
disabledKeys: disabledKeys.value,
208+
selectedNodes: service.selectedNodes.value,
209+
checkedNodes: service.checkedNodes.value,
210+
expandedKeys: service.expandedKeys.value,
211+
disabledKeys: service.disabledKeys.value,
188212
showCheckbox: props.showCheckbox,
189213
checkStrictly: props.checkStrictly,
190214
iconSlot: slots.icon,

src/components/VirtualTree/service.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import {NodeKey, TreeNodeOptions} from "./types";
2+
import {ref} from "vue";
3+
import {SelectionModel} from "../selections";
4+
5+
class TreeService {
6+
selectedNodes = ref(new SelectionModel<Required<TreeNodeOptions>>());
7+
checkedNodes = ref(new SelectionModel<Required<TreeNodeOptions>>(true));
8+
expandedKeys = ref(new SelectionModel<NodeKey>(true));
9+
disabledKeys = ref(new SelectionModel<NodeKey>(true));
10+
11+
defaultSelectedKey: NodeKey = '';
12+
defaultCheckedKeys: NodeKey[] = [];
13+
defaultExpandedKeys: NodeKey[] = [];
14+
defaultDisabledKeys: NodeKey[] = [];
15+
16+
flatTree: Required<TreeNodeOptions>[] = [];
17+
18+
constructor() {}
19+
20+
flattenTree(
21+
source: TreeNodeOptions[],
22+
defaultSelectedKey: NodeKey,
23+
defaultCheckedKeys: NodeKey[],
24+
defaultExpandedKeys: NodeKey[],
25+
defaultDisabledKeys: NodeKey[],
26+
): Required<TreeNodeOptions>[] {
27+
this.defaultSelectedKey = defaultSelectedKey;
28+
this.defaultCheckedKeys = defaultCheckedKeys;
29+
this.defaultExpandedKeys = defaultExpandedKeys;
30+
this.defaultDisabledKeys = defaultDisabledKeys;
31+
const result: Required<TreeNodeOptions>[] = [];
32+
const recursion = (list: TreeNodeOptions[], level = 0, parent: Required<TreeNodeOptions> | null = null) => {
33+
return list.map(item => {
34+
const flatNode: Required<TreeNodeOptions> = {
35+
...item,
36+
level,
37+
loading: false,
38+
hasChildren: item.hasChildren || false,
39+
parentKey: parent?.nodeKey || null,
40+
children: item.children || []
41+
};
42+
result.push(flatNode);
43+
if (defaultDisabledKeys.includes(item.nodeKey)) {
44+
this.disabledKeys.value.select(item.nodeKey);
45+
}
46+
if (defaultSelectedKey === item.nodeKey) {
47+
this.selectedNodes.value.select(flatNode);
48+
}
49+
if (defaultCheckedKeys.includes(item.nodeKey)) {
50+
this.checkedNodes.value.select(flatNode);
51+
}
52+
if (defaultExpandedKeys.includes(item.nodeKey) && item.children?.length) {
53+
this.expandedKeys.value.select(item.nodeKey);
54+
flatNode.children = recursion(item.children, level + 1, flatNode);
55+
}
56+
return flatNode;
57+
});
58+
}
59+
60+
recursion(source);
61+
return result;
62+
}
63+
64+
updateDownwards(checked: boolean, node: Required<TreeNodeOptions>) {
65+
const update = (children: Required<TreeNodeOptions>[]) => {
66+
if (children.length) {
67+
children.forEach(child => {
68+
const checkFunc = checked ? 'select' : 'deselect';
69+
this.checkedNodes.value[checkFunc](child);
70+
if (!checked) {
71+
this.removeDefaultCheckedKeys(child);
72+
}
73+
if (child.children?.length) {
74+
update(child.children as Required<TreeNodeOptions>[]);
75+
}
76+
});
77+
}
78+
}
79+
update(node.children as Required<TreeNodeOptions>[]);
80+
}
81+
82+
updateUpwards(targetNode: Required<TreeNodeOptions>, flatList: Required<TreeNodeOptions>[]) {
83+
const update = (node: Required<TreeNodeOptions>) => {
84+
if (node.parentKey != null) { // 说明是子节点
85+
const parentNode = flatList.find(item => item.nodeKey == node.parentKey)!;
86+
// console.log('parentNode', parentNode);
87+
const parentChecked = (parentNode.children as Required<TreeNodeOptions>[]).every((child) => this.checkedNodes.value.isSelected(child));
88+
if (parentChecked !== this.checkedNodes.value.isSelected(parentNode)) { // 父节点变了的话,就还要继续向上更新
89+
this.checkedNodes.value.toggle(parentNode);
90+
if (!parentChecked) {
91+
this.removeDefaultCheckedKeys(parentNode);
92+
}
93+
update(parentNode);
94+
}
95+
}
96+
}
97+
update(targetNode);
98+
}
99+
100+
removeDefaultCheckedKeys(node: TreeNodeOptions) {
101+
const inDefaultIndex = this.defaultCheckedKeys.findIndex(item => item === node.nodeKey);
102+
if (inDefaultIndex > -1) {
103+
this.defaultCheckedKeys.splice(inDefaultIndex, 1);
104+
}
105+
}
106+
107+
removeDefaultExpandedKeys(key: NodeKey) {
108+
const inDefaultIndex = this.defaultExpandedKeys.findIndex(item => item === key);
109+
if (inDefaultIndex > -1) {
110+
this.defaultExpandedKeys.splice(inDefaultIndex, 1);
111+
}
112+
}
113+
114+
}
115+
116+
117+
118+
119+
export { TreeService };

src/doc/BaseDemo.vue

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
<template>
22
<div class="demo">
33
<a-button @click="selectedNode">获取选中节点</a-button>
4-
<vir-tree ref="virTree" :source="list" :default-expanded-keys="defaultExpandedKeys" />
4+
<vir-tree
5+
ref="virTree"
6+
:source="list"
7+
:default-disabled-keys="defaultDisabledKeys"
8+
:default-selected-key="defaultSelectedKey"
9+
:default-expanded-keys="defaultExpandedKeys"
10+
/>
511
</div>
612
</template>
713

@@ -38,6 +44,8 @@
3844
const list = ref<TreeNodeOptions[]>([]);
3945
const virTree = ref<TreeInstance | null>(null);
4046
const defaultExpandedKeys = ['0-0', '0-1', '0-1-0'];
47+
const defaultSelectedKey = '0-0-1-0';
48+
const defaultDisabledKeys = ['0-0-1'];
4149
onMounted(() => {
4250
list.value = recursion();
4351
});
@@ -48,7 +56,9 @@
4856
list,
4957
virTree,
5058
selectedNode,
51-
defaultExpandedKeys
59+
defaultExpandedKeys,
60+
defaultSelectedKey,
61+
defaultDisabledKeys
5262
}
5363
}
5464
});

0 commit comments

Comments
 (0)