Skip to content

Commit

Permalink
fix(tree): 完善受控逻辑,解决 onChange 事件触发时,组件状态传递有延迟的问题 (#3509)
Browse files Browse the repository at this point in the history
* fix(tree): tree 组件,完善受控逻辑,解决 onChange 事件触发时,组件状态传递有延迟的问题

* test(unit): tree, update snapshot
  • Loading branch information
TabSpace authored Oct 23, 2023
1 parent 94f5221 commit 6a00f49
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 65 deletions.
127 changes: 119 additions & 8 deletions src/tree/__tests__/api.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ describe('Tree:api', () => {
expect(wrapper.find('[data-value="t1"]').text()).toBe('节点1');
});

it('可以设置节点属性 checked触发视图更新', async () => {
it('可以设置节点属性 checked, 触发视图更新', async () => {
const data = [
{
value: 't1',
Expand All @@ -142,28 +142,62 @@ describe('Tree:api', () => {
],
},
];
let changeParams = null;
let changeCount = 0;
const onChange = (checked, context) => {
changeCount += 1;
changeParams = {
checked,
context,
};
};
const wrapper = mount({
data() {
return {
checked: [],
};
},
render() {
return <Tree ref="tree" transition={false} data={data} expandAll={true} checkable />;
return (
<Tree
ref="tree"
expandAll
checkable
transition={false}
data={data}
v-model={this.checked}
onChange={onChange}
/>
);
},
});

await delay(10);
await delay(1);
const { tree } = wrapper.vm.$refs;
tree.setItem('t1', {
checked: true,
});
tree.setItem('t2', {
checked: true,
});
await delay(10);

expect(wrapper.vm.checked.length).toBe(2);
expect(wrapper.vm.checked[0]).toBe('t1.1');
expect(wrapper.vm.checked[1]).toBe('t2.1');
await delay(1);
expect(wrapper.find('[data-value="t1"] .t-checkbox').classes('t-is-checked')).toBe(true);
expect(wrapper.find('[data-value="t1.1"] .t-checkbox').classes('t-is-checked')).toBe(true);
expect(wrapper.find('[data-value="t2"] .t-checkbox').classes('t-is-checked')).toBe(true);
expect(wrapper.find('[data-value="t2.1"] .t-checkbox').classes('t-is-checked')).toBe(true);

expect(changeCount).toBe(2);
expect(changeParams.checked.length).toBe(2);
expect(changeParams.checked[0]).toBe('t1.1');
expect(changeParams.checked[1]).toBe('t2.1');
expect(changeParams.context.node.value).toEqual('t2');
});

it('可以设置节点属性 expanded触发视图更新', async () => {
it('可以设置节点属性 expanded, 触发视图更新', async () => {
const data = [
{
value: 't1',
Expand All @@ -182,27 +216,104 @@ describe('Tree:api', () => {
],
},
];

let expandParams = null;
let expandCount = 0;
const onExpand = (expanded, context) => {
expandCount += 1;
expandParams = {
expanded,
context,
};
};
const wrapper = mount({
render() {
return <Tree ref="tree" transition={false} data={data} />;
return <Tree ref="tree" transition={false} data={data} onExpand={onExpand} />;
},
});

await delay(10);
await delay(1);
const { tree } = wrapper.vm.$refs;
tree.setItem('t1', {
expanded: true,
});
tree.setItem('t2', {
expanded: true,
});
await delay(10);
await delay(1);
const t1d1 = wrapper.find('[data-value="t1.1"]');
expect(t1d1.exists()).toBe(true);
expect(t1d1.classes('t-tree__item--visible')).toBe(true);
const t2d1 = wrapper.find('[data-value="t2.1"]');
expect(t2d1.exists()).toBe(true);
expect(t2d1.classes('t-tree__item--visible')).toBe(true);

expect(expandCount).toBe(2);
expect(expandParams.expanded.length).toBe(2);
expect(expandParams.expanded[0]).toBe('t1');
expect(expandParams.expanded[1]).toBe('t2');
expect(expandParams.context.node.value).toEqual('t2');
});

it('可以设置节点属性 actived, 触发视图更新', async () => {
const data = [
{
value: 't1',
children: [
{
value: 't1.1',
},
],
},
{
value: 't2',
children: [
{
value: 't2.1',
},
],
},
];

let activeParams = null;
let activeCount = 0;
const onActive = (actived, context) => {
activeCount += 1;
activeParams = {
actived,
context,
};
};
const wrapper = mount({
render() {
return <Tree ref="tree" activable expandAll transition={false} data={data} onActive={onActive} />;
},
});

await delay(1);
const t1d1 = wrapper.find('[data-value="t1.1"]');
const t2d1 = wrapper.find('[data-value="t2.1"]');

const { tree } = wrapper.vm.$refs;
tree.setItem('t1.1', {
actived: true,
});
expect(activeCount).toBe(1);
expect(activeParams.actived.length).toBe(1);
expect(activeParams.actived[0]).toBe('t1.1');
expect(activeParams.context.node.value).toEqual('t1.1');
await delay(1);
expect(t1d1.classes('t-is-active')).toBe(true);

tree.setItem('t2.1', {
actived: true,
});
expect(activeCount).toBe(2);
expect(activeParams.actived.length).toBe(1);
expect(activeParams.actived[0]).toBe('t2.1');
expect(activeParams.context.node.value).toEqual('t2.1');
await delay(1);
expect(t2d1.classes('t-is-active')).toBe(true);
});
});

Expand Down
6 changes: 6 additions & 0 deletions src/tree/__tests__/event.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ describe('Tree:props:events', () => {
expect(rsActived.length).toBe(1);
expect(rsActived[0]).toBe('t2');
expect(rsContext.node.value).toBe('t2');
expect(rsContext.node.actived).toBe(true);
}, 300);

it('active 事件可触发', async () => {
Expand Down Expand Up @@ -98,6 +99,7 @@ describe('Tree:props:events', () => {
expect(rsActived.length).toBe(1);
expect(rsActived[0]).toBe('t2');
expect(rsContext.node.value).toBe('t2');
expect(rsContext.node.actived).toBe(true);
}, 300);
});

Expand Down Expand Up @@ -161,6 +163,7 @@ describe('Tree:props:events', () => {
expect(rsExpanded.length).toBe(1);
expect(rsExpanded[0]).toBe('t2');
expect(rsContext.node.value).toBe('t2');
expect(rsContext.node.expanded).toBe(true);
}, 300);

it('expand 事件可触发', async () => {
Expand Down Expand Up @@ -222,6 +225,7 @@ describe('Tree:props:events', () => {
expect(rsExpanded.length).toBe(1);
expect(rsExpanded[0]).toBe('t2');
expect(rsContext.node.value).toBe('t2');
expect(rsContext.node.expanded).toBe(true);
}, 300);
});

Expand Down Expand Up @@ -286,6 +290,7 @@ describe('Tree:props:events', () => {
expect(rsValue.length).toBe(1);
expect(rsValue[0]).toBe('t2.1');
expect(rsContext.node.value).toBe('t2');
expect(rsContext.node.checked).toBe(true);
}, 300);

it('change 事件可触发', async () => {
Expand Down Expand Up @@ -348,6 +353,7 @@ describe('Tree:props:events', () => {
expect(rsValue.length).toBe(1);
expect(rsValue[0]).toBe('t2.1');
expect(rsContext.node.value).toBe('t2');
expect(rsContext.node.checked).toBe(true);
}, 300);
});

Expand Down
15 changes: 5 additions & 10 deletions src/tree/_example/checkable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default {
valueMode: 'onlyLeaf',
checkable: true,
checkStrictly: false,
allChecked: ['1.1.1.1'],
allChecked: [],
valueOptions: [
{
value: 'onlyLeaf',
Expand Down Expand Up @@ -149,19 +149,14 @@ export default {
},
methods: {
onClick(context) {
console.info('onClick:', context);
console.info('onClick context:', context);
const { node } = context;
console.info(node.value, 'checked:', node.checked);
console.info(node.value, 'onClick context.node.checked:', node.checked);
},
onChange(checked, context) {
console.info('onChange:', checked, context);
console.info('onChange checked:', checked, 'context:', context);
const { node } = context;
console.info(node.value, 'checked:', node.checked);
},
propOnChange(checked, context) {
console.info('propOnChange:', checked, context);
const { node } = context;
console.info(node.value, 'checked:', node.checked);
console.info(node.value, 'onChange context.node.checked:', node.checked);
},
selectInvert() {
const { tree } = this.$refs;
Expand Down
57 changes: 39 additions & 18 deletions src/tree/_example/controlled.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,39 +169,60 @@ export default {
this.expanded = ['1', '1.2'];
},
onClick(context) {
console.info('onClick:', context);
const { node } = context;
console.info(node.value, 'checked:', node.checked, 'expanded:', node.expanded, 'actived:', node.actived);
console.info('onClick context:', context);
},
onChange(vals, context) {
console.info('onChange:', vals, context);
const checked = vals.filter((val) => val !== '2.1');
console.info('节点 2.1 不允许选中');
console.info('onChange value:', vals, 'context:', context);
const { node } = context;
// onChange 事件发生时,context.node 状态预先发生变更,此时拿到预先变更的节点状态
console.info(node.value, 'context.node.checked:', node.checked);
if (this.syncProps) {
const checked = vals.filter((val) => {
if (val === '2.1') {
console.info('节点 2.1 不允许选中');
return false;
}
return true;
});
// 受控状态下, tree 的 props.value 可被修改为预期的值
console.log('before set this.checked, expect checked:', checked);
this.checked = checked;
}
const { node } = context;
console.info(node.value, 'checked:', node.checked);
// 赋值变更后的选中态之后,nextTick 之后触发视图更新
// node.checked 状态发生变更,符合 tree 的 props.value 的取值
this.$nextTick(() => {
console.info(node.value, 'nextTick context.node.checked:', node.checked);
});
},
onActive(vals, context) {
console.info('onActive:', vals, context);
const actived = vals.filter((val) => val !== '2.2');
console.info('节点 2.2 不允许激活', actived);
console.info('onActive actived:', vals, 'context:', context);
const { node } = context;
console.info(node.value, 'context.node.actived:', node.actived);
const actived = vals.filter((val) => {
if (val === '2.2') {
console.info('节点 2.2 不允许激活');
return false;
}
return true;
});
if (this.syncProps) {
this.actived = actived;
}
const { node } = context;
console.info(node.value, 'actived:', node.actived);
},
onExpand(vals, context) {
console.info('onExpand:', vals, context);
const expanded = vals.filter((val) => val !== '2.3');
console.info('节点 2.3 不允许展开', expanded);
console.info('onExpand expanded:', vals, 'context:', context);
const { node } = context;
console.info(node.value, 'context.node.expanded:', node.expanded);
const expanded = vals.filter((val) => {
if (val === '2.3') {
console.info('节点 2.3 不允许展开');
return false;
}
return true;
});
if (this.syncProps) {
this.expanded = expanded;
}
const { node } = context;
console.info(node.value, 'expanded:', node.expanded);
},
},
};
Expand Down
Loading

0 comments on commit 6a00f49

Please sign in to comment.