Skip to content

Commit d2e1ba1

Browse files
jxhhdxkagol
authored andcommitted
fix(tree): 解决勾选父节点禁用状态下的子节点也会被勾选的问题
1 parent da41b83 commit d2e1ba1

File tree

3 files changed

+68
-14
lines changed

3 files changed

+68
-14
lines changed

packages/devui-vue/devui/tree/__tests__/checkable-tree/checkable-tree-data.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { TreeData } from '../../';
1+
import type { ITreeNode } from '../../';
22

3-
export const checkableTreeData: TreeData = [
3+
export const checkableTreeData: ITreeNode[] = [
44
{
55
label: 'Parent node 1',
66
children: [
@@ -13,3 +13,27 @@ export const checkableTreeData: TreeData = [
1313
},
1414
{ label: 'Leaf node 2' },
1515
];
16+
17+
export const disabledCheckableTreeData: ITreeNode[] = [
18+
{
19+
label: 'Parent node 1',
20+
expanded: true,
21+
children: [
22+
{
23+
label: 'Parent node 1-1',
24+
disableToggle: true,
25+
disableSelect: true,
26+
disableCheck: true,
27+
children: [{ label: 'Leaf node 1-1-1' }],
28+
},
29+
{
30+
label: 'Leaf node 1-2',
31+
disableCheck: true,
32+
},
33+
],
34+
},
35+
{
36+
label: 'Leaf node 2',
37+
disableSelect: true,
38+
},
39+
];

packages/devui-vue/devui/tree/__tests__/checkable-tree/checkable-tree.spec.tsx

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import type { ComponentPublicInstance, ComponentInternalInstance } from 'vue';
2-
import { onMounted, ref } from 'vue';
2+
import { onMounted, ref, nextTick } from 'vue';
33
import { mount, VueWrapper } from '@vue/test-utils';
44
import { Tree, ICheck } from '../../';
5-
import { checkableTreeData } from './checkable-tree-data';
5+
import { checkableTreeData, disabledCheckableTreeData } from './checkable-tree-data';
66
import { useNamespace } from '../../../shared/hooks/use-namespace';
77

8-
jest.mock('../../../locale/create', () => ({
9-
createI18nTranslate: () => jest.fn(),
10-
}));
11-
128
type ITreeFactory = { expandAllNodes: () => void };
9+
const ns = useNamespace('tree', true);
1310
const checkBoxNs = useNamespace('checkbox', true);
1411

1512
describe('Checkable tree', () => {
@@ -159,4 +156,31 @@ describe('Checkable tree', () => {
159156
await wrapper2.get('.disable').trigger('click');
160157
expect(wrapper2.findAll(checkBoxNs.b())[0].classes()).toContain('active');
161158
});
159+
160+
it("When the parent node is checked, the child node in disabled status should not be checked", async () => {
161+
const curWrapper = mount({
162+
setup() {
163+
const data = ref(disabledCheckableTreeData);
164+
return () => {
165+
return (
166+
<>
167+
<Tree data={data.value} check />
168+
</>
169+
);
170+
};
171+
}
172+
});
173+
await nextTick();
174+
const nodes = curWrapper.findAll(ns.e('node'));
175+
const checkbox = checkBoxNs.b();
176+
expect(nodes).toHaveLength(4);
177+
expect(nodes[0].find(checkbox).classes()).toContain('unchecked');
178+
expect(nodes[1].find(checkbox).classes()).toContain('unchecked');
179+
expect(nodes[2].find(checkbox).classes()).toContain('unchecked');
180+
await nodes[0].get('label').trigger('click');
181+
expect(nodes[0].find(checkbox).classes()).toContain('active');
182+
expect(nodes[1].find(checkbox).classes()).toContain('unchecked');
183+
expect(nodes[2].find(checkbox).classes()).toContain('unchecked');
184+
curWrapper.unmount();
185+
});
162186
});

packages/devui-vue/devui/tree/src/composables/use-check.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ref, Ref, SetupContext } from 'vue';
22
import { ICheckStrategy, IInnerTreeNode, IUseCore, IUseCheck } from './use-tree-types';
3-
3+
type ISetNodeValue = Parameters<IUseCore['setNodeValue']>;
44
export default function (
55
options: Ref<{ checkStrategy: ICheckStrategy }> = ref({ checkStrategy: 'both' as ICheckStrategy })
66
) {
@@ -12,6 +12,12 @@ export default function (
1212
context.emit('check-change', node);
1313
};
1414

15+
const setNodeValueInAvailable = (node: ISetNodeValue[0], key: ISetNodeValue[1], value: ISetNodeValue[2]) => {
16+
if (!node.disableCheck) {
17+
setNodeValue(node, key, value);
18+
}
19+
};
20+
1521
const uncheckNode = (node: IInnerTreeNode): void => {
1622
setNodeValue(node, 'checked', false);
1723
context.emit('check-change', node);
@@ -30,17 +36,17 @@ export default function (
3036
// 子节点选中后触发
3137
if (checked) {
3238
if (!parentNode.checked) {
33-
setNodeValue(parentNode, 'checked', true);
39+
setNodeValueInAvailable(parentNode, 'checked', true);
3440
}
3541
} else {
3642
// 子节点取消后触发
3743
const siblingNodes = getChildren(parentNode);
3844
const checkedSiblingNodes = siblingNodes.filter(item => item.checked && item.id !== node.id);
3945
// 子节点全部是取消状态
4046
if (checkedSiblingNodes.length === 0) {
41-
setNodeValue(parentNode, 'checked', false);
47+
setNodeValueInAvailable(parentNode, 'checked', false);
4248
} else {
43-
setNodeValue(parentNode, 'checked', true);
49+
setNodeValueInAvailable(parentNode, 'checked', true);
4450
childChecked = true;
4551
}
4652
}
@@ -57,14 +63,14 @@ export default function (
5763
context.emit('check-change', node);
5864

5965
if (['downward', 'both'].includes(options.value.checkStrategy)) {
60-
getChildren(node).forEach(item => setNodeValue(item, 'checked', false));
66+
getChildren(node).forEach(item => setNodeValueInAvailable(item, 'checked', false));
6167
}
6268
} else {
6369
setNodeValue(node, 'checked', true);
6470
context.emit('check-change', node);
6571

6672
if (['downward', 'both'].includes(options.value.checkStrategy)) {
67-
getChildren(node).forEach(item => setNodeValue(item, 'checked', true));
73+
getChildren(node).forEach(item => setNodeValueInAvailable(item, 'checked', true));
6874
}
6975
}
7076

0 commit comments

Comments
 (0)