Angular:如何仅在点击Calculate关闭新窗口时触发Snackbar?
仅通过Calculate按钮关闭窗口时触发Snackbar的优化方案
问题背景
我从无关联的Calculation List组件中打开名为New Calculation的新窗口,当前实现代码如下:
const windowHandler: Window = window.open(appUrl); const calculateSnackbarInterval = setInterval((): void => { this.calculateOpened = true; this.ref.detectChanges(); if (windowHandler.closed) { this.snackBarService.openSnackBar({ type: 'info', message: this.translate.instant(this.getTranslateKeyForSnackBar()), actions: [ { label: this.translate.instant(`snackbar.actions.abort`), action: SnackbarAction.ABORT, }, ], }); this.calculateOpened = false; this.ref.detectChanges(); this.pullingIntervalDelete?.unsubscribe(); clearInterval(this.maximumPullingInterval); this.startPullingInterval(); clearInterval(calculateSnackbarInterval); } }, 1000);
当前无论通过Cancel按钮、浏览器关闭还是Calculate按钮关闭New Calculation窗口,Calculation List组件都会弹出snackbar。需求是仅在通过Calculate按钮关闭窗口时触发该snackbar。
我已想到两种方案,但各有缺点:
- 方案1:使用local storage存储关闭窗口的按钮信息,在windowHandler中读取
- 缺点:存在安全隐患,用户可篡改local storage内容
- 方案2:构建专用服务响应Calculate按钮的事件
- 缺点:需添加大量监听器和依赖,略显冗余
请问是否有更优的实现方式?
更优实现方案
推荐使用**window.postMessage跨窗口通信**的方式,安全且实现简洁,具体步骤如下:
1. 父窗口(Calculation List组件)修改
打开子窗口后,添加消息监听,并在窗口关闭时根据标记判断是否弹出snackbar:
const windowHandler: Window = window.open(appUrl); let isCalculationCompleted = false; // 定义消息监听函数,便于后续移除 const messageListener = (event: MessageEvent) => { // 验证消息来源和发送方域名,确保安全 if (event.source === windowHandler && event.origin === window.origin) { if (event.data.type === 'CALCULATION_COMPLETED') { isCalculationCompleted = true; } } }; window.addEventListener('message', messageListener); const calculateSnackbarInterval = setInterval((): void => { this.calculateOpened = true; this.ref.detectChanges(); if (windowHandler.closed) { // 仅在通过Calculate按钮关闭时触发snackbar if (isCalculationCompleted) { this.snackBarService.openSnackBar({ type: 'info', message: this.translate.instant(this.getTranslateKeyForSnackBar()), actions: [ { label: this.translate.instant(`snackbar.actions.abort`), action: SnackbarAction.ABORT, }, ], }); } this.calculateOpened = false; this.ref.detectChanges(); this.pullingIntervalDelete?.unsubscribe(); clearInterval(this.maximumPullingInterval); this.startPullingInterval(); clearInterval(calculateSnackbarInterval); // 移除消息监听,避免内存泄漏 window.removeEventListener('message', messageListener); } }, 1000);
2. 子窗口(New Calculation)修改
在Calculate按钮的点击事件中,向父窗口发送完成信号后关闭自身:
// Calculate按钮点击事件处理 onCalculateClick(): void { // 执行计算逻辑... // 向父窗口发送计算完成消息 window.opener?.postMessage({ type: 'CALCULATION_COMPLETED' }, window.origin); // 关闭当前窗口 window.close(); }
方案优势
- 安全性高:通过验证
event.source和event.origin,可避免恶意页面的消息干扰 - 实现简洁:无需额外存储或复杂服务,仅需跨窗口消息通信
- 无冗余依赖:利用浏览器原生API,不需要引入额外库或服务
内容的提问来源于stack exchange,提问作者mariaILikeIt
相关产品推荐
相关产品推荐

