You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 18:20:48