Skip to content

Commit

Permalink
fix(tree): tree 组件, value, active, expanded 属性, 支持数组操作触发视图变更 (#3682)
Browse files Browse the repository at this point in the history
* fix(tree): tree 组件, value, active, expanded 属性, 支持数组操作触发视图变更

* refactor(tree): tree 组件, 改进属性监听语句代码结构

* fix(tree): tree 组件,解决 value 传递 undefined,可能导致视图操作报错的问题
  • Loading branch information
TabSpace committed Dec 5, 2023
1 parent e184a24 commit d208bbb
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 21 deletions.
45 changes: 45 additions & 0 deletions src/tree/__tests__/activable.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mount } from '@vue/test-utils';
import Tree from '@/src/tree/index.ts';
import { delay } from './kit';
import { ref } from './adapt';

describe('Tree:activable', () => {
vi.useRealTimers();
Expand Down Expand Up @@ -215,6 +216,50 @@ describe('Tree:activable', () => {
await wrapper.find('[data-value="t1"] .t-tree__label').trigger('click');
expect(wrapper.find('[data-value="t1"]').classes('t-is-active')).toBe(false);
});

it('操作 actived 数组可变更激活节点', async () => {
const data = [
{
value: 't1',
children: [
{
value: 't1.1',
},
{
value: 't1.2',
},
],
},
];
const refActived = ref(['t1.1']);
const wrapper = mount({
render() {
return (
<Tree ref="tree" expand-all data={data} activable actived={refActived.value} transition={false}></Tree>
);
},
});
await delay(1);
expect(wrapper.find('[data-value="t1"]').classes('t-is-active')).toBe(false);
expect(wrapper.find('[data-value="t1.1"]').classes('t-is-active')).toBe(true);
expect(wrapper.find('[data-value="t1.2"]').classes('t-is-active')).toBe(false);

refActived.value.push('t1.2');
// refActived.value 为 t1.1, t1.2
// 但由于默认为单选机制,仅第一个被激活
await delay(1);
expect(wrapper.find('[data-value="t1"]').classes('t-is-active')).toBe(false);
expect(wrapper.find('[data-value="t1.1"]').classes('t-is-active')).toBe(true);
expect(wrapper.find('[data-value="t1.2"]').classes('t-is-active')).toBe(false);

refActived.value.shift();
// refActived.value 为 t1.2
// 第一个激活节点变更为了 t1.2
await delay(1);
expect(wrapper.find('[data-value="t1"]').classes('t-is-active')).toBe(false);
expect(wrapper.find('[data-value="t1.1"]').classes('t-is-active')).toBe(false);
expect(wrapper.find('[data-value="t1.2"]').classes('t-is-active')).toBe(true);
});
});

describe('props.activeMultiple', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/tree/__tests__/adapt.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { defineComponent } from 'vue';
export { defineComponent, ref } from 'vue';
35 changes: 35 additions & 0 deletions src/tree/__tests__/checkable.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mount } from '@vue/test-utils';
import Tree from '@/src/tree/index.ts';
import { delay } from './kit';
import { ref } from './adapt';

describe('Tree:checkable', () => {
vi.useRealTimers();
Expand Down Expand Up @@ -141,6 +142,40 @@ describe('Tree:checkable', () => {
expect(wrapper.find('[data-value="t1.1"] .t-checkbox').classes('t-is-checked')).toBe(false);
expect(wrapper.find('[data-value="t1.2"] .t-checkbox').classes('t-is-checked')).toBe(true);
});

it('操作 value 数组可变更节点选中状态', async () => {
const data = [
{
value: 't1',
children: [
{
value: 't1.1',
},
{
value: 't1.2',
},
],
},
];

const refChecked = ref(['t1.1']);
const wrapper = mount({
render() {
return <Tree transition={false} data={data} checkable expandAll value={refChecked.value}></Tree>;
},
});
expect(wrapper.find('[data-value="t1"] .t-checkbox').classes('t-is-checked')).toBe(false);
expect(wrapper.find('[data-value="t1"] .t-checkbox').classes('t-is-indeterminate')).toBe(true);
expect(wrapper.find('[data-value="t1.1"] .t-checkbox').classes('t-is-checked')).toBe(true);
expect(wrapper.find('[data-value="t1.2"] .t-checkbox').classes('t-is-checked')).toBe(false);

refChecked.value.push('t1.2');
await delay(1);
expect(wrapper.find('[data-value="t1"] .t-checkbox').classes('t-is-checked')).toBe(true);
expect(wrapper.find('[data-value="t1"] .t-checkbox').classes('t-is-indeterminate')).toBe(false);
expect(wrapper.find('[data-value="t1.1"] .t-checkbox').classes('t-is-checked')).toBe(true);
expect(wrapper.find('[data-value="t1.2"] .t-checkbox').classes('t-is-checked')).toBe(true);
});
});

describe('props.checkStrictly', () => {
Expand Down
53 changes: 53 additions & 0 deletions src/tree/__tests__/expand.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mount } from '@vue/test-utils';
import Tree from '@/src/tree/index.ts';
import { delay } from './kit';
import { ref } from './adapt';

describe('Tree:expand', () => {
vi.useRealTimers();
Expand Down Expand Up @@ -152,6 +153,58 @@ describe('Tree:expand', () => {
expect(t2d1.classes('t-tree__item--visible')).toBe(false);
expect(t2d1.classes('t-tree__item--hidden')).toBe(true);
});

it('操作 expanded 数组可变更展开节点', async () => {
const data = [
{
value: 't1',
children: [
{
value: 't1.1',
},
],
},
{
value: 't2',
children: [
{
value: 't2.1',
},
],
},
];
const refExpanded = ref(['t2']);
const wrapper = mount({
render() {
return <Tree data={data} expanded={refExpanded.value} transition={false}></Tree>;
},
});

expect(wrapper.find('[data-value="t1.1"]').exists()).toBe(false);
expect(wrapper.find('[data-value="t2.1"]').exists()).toBe(true);

await delay(1);

let t1d1 = wrapper.find('[data-value="t1.1"]');
const t2d1 = wrapper.find('[data-value="t2.1"]');
expect(t1d1.exists()).toBe(false);
expect(t2d1.exists()).toBe(true);
expect(t2d1.classes('t-tree__item--visible')).toBe(true);
expect(t2d1.classes('t-tree__item--hidden')).toBe(false);

refExpanded.value.push('t1');
await delay(1);
t1d1 = wrapper.find('[data-value="t1.1"]');
expect(t1d1.exists()).toBe(true);
expect(t1d1.classes('t-tree__item--visible')).toBe(true);
expect(t1d1.classes('t-tree__item--hidden')).toBe(false);

refExpanded.value.shift();
await delay(1);
expect(t2d1.exists()).toBe(true);
expect(t2d1.classes('t-tree__item--visible')).toBe(false);
expect(t2d1.classes('t-tree__item--hidden')).toBe(true);
});
});

describe('props.expandLevel', () => {
Expand Down
6 changes: 3 additions & 3 deletions src/tree/hooks/useTreeAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function useTreeAction(state: TypeTreeState) {
});
setTExpanded(expanded, evtCtx);
if (evtCtx.trigger !== 'setItem') {
store.replaceExpanded(tExpanded.value as TreeNodeValue[]);
store.replaceExpanded((tExpanded.value || []) as TreeNodeValue[]);
}
return expanded;
};
Expand All @@ -67,7 +67,7 @@ export default function useTreeAction(state: TypeTreeState) {
});
setTActived(actived, evtCtx);
if (evtCtx.trigger !== 'setItem') {
store.replaceActived(tActived.value as TreeNodeValue[]);
store.replaceActived((tActived.value || []) as TreeNodeValue[]);
}
return actived;
};
Expand Down Expand Up @@ -95,7 +95,7 @@ export default function useTreeAction(state: TypeTreeState) {
setTValue(checked, evtCtx);
// 这是针对受控执行的操作,如果 props.value 未变更,则执行还原操作
if (evtCtx.trigger !== 'setItem') {
store.replaceChecked(tValue.value as TreeNodeValue[]);
store.replaceChecked((tValue.value || []) as TreeNodeValue[]);
}
return checked;
};
Expand Down
43 changes: 26 additions & 17 deletions src/tree/hooks/useTreeStore.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pick from 'lodash/pick';
import { TreeStore } from '../../_common/js/tree/tree-store';
import { watch } from '../adapt';
import { watch, TypeRef } from '../adapt';
import {
TreeProps,
TypeValueMode,
Expand All @@ -21,9 +21,12 @@ export default function useTreeStore(state: TypeTreeState) {
filter,
});

const [tValue] = state.vmValue;
const [tActived] = state.vmActived;
const [tExpanded] = state.vmExpanded;
// tValue 就是 refProps.value
const tValue = state.vmValue[0] as TypeRef<TreeNodeValue[]>;
// tActived 就是 refProps.actived
const tActived = state.vmActived[0] as TypeRef<TypeTNodeValue[]>;
// tExpanded 就是 refProps.expanded
const tExpanded = state.vmExpanded[0] as TypeRef<TypeTNodeValue[]>;

// 同步 Store 选项
const updateStoreConfig = () => {
Expand Down Expand Up @@ -185,20 +188,26 @@ export default function useTreeStore(state: TypeTreeState) {
initStore();
// 设置初始化状态
state.setStore(store);

// 配置属性监听
// tValue 就是 refProps.value
watch(tValue, (nVal: TreeNodeValue[]) => {
store.replaceChecked(nVal);
});
// tExpanded 就是 refProps.expanded
watch(tExpanded, (nVal: TreeNodeValue[]) => {
store.replaceExpanded(nVal);
});
// tActived 就是 refProps.actived
watch(tActived, (nVal: TreeNodeValue[]) => {
store.replaceActived(nVal);
});
watch(
() => [...(tValue.value || [])],
(nVal: TreeNodeValue[]) => {
store.replaceChecked(nVal);
},
);
watch(
() => [...(tExpanded.value || [])],
(nVal: TreeNodeValue[]) => {
store.replaceExpanded(nVal);
},
);
watch(
() => [...(tActived.value || [])],
(nVal: TreeNodeValue[]) => {
store.replaceActived(nVal);
},
);

watch(refProps.filter, (nVal, previousVal) => {
checkFilterExpand(nVal, previousVal);
});
Expand Down

0 comments on commit d208bbb

Please sign in to comment.