diff --git a/packages/components/message-item/message-item.ts b/packages/components/message-item/message-item.ts index 6b87418441..893f37645d 100644 --- a/packages/components/message-item/message-item.ts +++ b/packages/components/message-item/message-item.ts @@ -94,7 +94,7 @@ export default class Message extends SuperComponent { this.memoInitialData(); }, detached() { - this.clearMessageAnimation(); + this.reset(); }, }; diff --git a/packages/components/message/__test__/index.test.js b/packages/components/message/__test__/index.test.js index 742ef0a83f..f66095e3a6 100644 --- a/packages/components/message/__test__/index.test.js +++ b/packages/components/message/__test__/index.test.js @@ -182,6 +182,53 @@ describe('message', () => { }); }); + describe('lifecycle', () => { + it(': clears the duration timer when detached', () => { + const messageItem = load(path.resolve(__dirname, `../../message-item/message-item`), 't-message-item'); + const comp = simulate.render(messageItem, { + content: 'message before navigate back', + duration: 5000, + offset: [20, 32], + }); + comp.attach(document.createElement('parent-wrapper')); + + comp.instance.show(); + expect(comp.instance.closeTimeoutContext).not.toBe(0); + + comp.detach(); + const { closeTimeoutContext } = comp.instance; + if (closeTimeoutContext) clearTimeout(closeTimeoutContext); + expect(closeTimeoutContext).toBe(0); + }); + + it(': hides each message at most once when an instance cannot remove itself', () => { + const id = simulate.load({ + template: ``, + usingComponents: { + 't-message': message, + }, + }); + const comp = simulate.render(id); + comp.attach(document.createElement('parent-wrapper')); + const $message = comp.querySelector('#t-message'); + const firstHide = jest + .fn() + .mockImplementationOnce(() => {}) + .mockImplementationOnce(() => { + throw new Error('hide called repeatedly'); + }); + const secondHide = jest.fn(); + + $message.instance.instances = [{ hide: firstHide }, { hide: secondHide }]; + + expect(() => $message.instance.hideAll()).not.toThrow(); + expect(firstHide).toHaveBeenCalledTimes(1); + expect(secondHide).toHaveBeenCalledTimes(1); + $message.instance.instances = []; + comp.detach(); + }); + }); + describe('multiple', () => { it(': message-count-gap', async () => { const id = simulate.load({ diff --git a/packages/components/message/message.ts b/packages/components/message/message.ts index 061453aa37..8d8505ab1f 100644 --- a/packages/components/message/message.ts +++ b/packages/components/message/message.ts @@ -110,7 +110,7 @@ export default class Message extends SuperComponent { () => { const offsetHeight = this.getOffsetHeight(); const instance = this.showMessageItem(msgObj, msgObj.id, offsetHeight); - if (this.instances) { + if (instance) { this.instances.push(instance); this.index += 1; } @@ -146,11 +146,11 @@ export default class Message extends SuperComponent { showMessageItem(options: MessageProps, id: string, offsetHeight: number) { const instance = this.selectComponent(`#${id}`); if (instance) { + instance.onHide = () => { + this.close(id); + }; instance.resetData(() => { instance.setData(options, instance.show.bind(instance, offsetHeight)); - instance.onHide = () => { - this.close(id); - }; }); return instance; @@ -183,11 +183,8 @@ export default class Message extends SuperComponent { * 移除全部消息 */ hideAll() { - // 消息移除后也会移除instance,下标不用增加,直至全部删除 - for (let i = 0; i < this.instances.length; ) { - const instance = this.instances[i]; - instance.hide(); - } + // 使用快照,避免依赖子实例在 hide 回调中同步修改 instances。 + [...this.instances].forEach((instance) => instance?.hide()); } /**