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

Chrome v95及以上版本JS弹窗拦截检测代码失效问题求助

问题根因

这个异常是Chrome 95+版本的弹窗权限缓存机制导致的,原有检测逻辑存在覆盖盲区:

  • 站点首次全新加载时,Chrome会实时读取当前站点的弹窗权限配置:如果权限为拦截,window.open会直接返回null,或者返回一个立即标记为关闭的空窗口对象,原有的三重判断(!newWin / newWin.closed / closed属性不存在)可以正常命中拦截状态。
  • 一旦用户曾给当前站点授予过弹窗权限,Chrome会在渲染进程中缓存「允许弹窗」的权限标记。即使用户后续在站点设置中把权限改回拦截,这个缓存不会实时同步给已经打开的页面上下文。此时调用window.open不会返回null,而是返回一个待拦截状态的窗口引用:这个引用的closed属性初始值为false,closed属性本身也存在,原有的判断条件全部不满足,就会误判为弹窗允许。
  • 这个场景下Chrome虽然返回了窗口引用,但会在后台静默拦截弹窗,不会真的加载目标页面,也不会让弹窗出现在用户视野里。
修复方案

原有的同步判断逻辑无法覆盖权限缓存场景,需要补充异步检测逻辑,结合窗口的生命周期状态综合判断,修复后的完整实现如下:

/**
 * 检测弹窗是否被拦截
 * @param {string} url 要打开的目标地址
 * @returns {Promise<boolean>} true-弹窗未被拦截 false-弹窗被拦截
 */
function checkPopupBlocked(url) {
  return new Promise((resolve) => {
    const newWin = window.open(url);
    // 第一层:原有同步检测逻辑,覆盖首次加载直接拦截的场景
    if (!newWin || newWin.closed || typeof newWin.closed === 'undefined') {
      resolve(false);
      return;
    }

    let detectCount = 0;
    // 第二层:异步轮询检测,覆盖权限缓存后延迟拦截的场景
    const detectTimer = setInterval(() => {
      detectCount++;
      try {
        // 尝试读取窗口内部地址,触发同域/拦截状态校验
        newWin.location.href;
        if (newWin.closed) {
          clearInterval(detectTimer);
          resolve(false);
          return;
        }
        // 连续检测25次(共2.5秒)窗口仍正常存在,判定为未拦截
        if (detectCount > 25) {
          clearInterval(detectTimer);
          resolve(true);
        }
      } catch (e) {
        // 跨域正常弹窗访问location会抛跨域错误,属于正常现象,仅当窗口被自动关闭时判定为拦截
        if (newWin.closed) {
          clearInterval(detectTimer);
          resolve(false);
          return;
        }
        if (detectCount > 25) {
          clearInterval(detectTimer);
          resolve(true);
        }
      }
    }, 100);

    // 兜底监听窗口提前关闭事件
    newWin.addEventListener('beforeunload', () => {
      setTimeout(() => {
        if (newWin.closed && detectCount < 10) {
          clearInterval(detectTimer);
          resolve(false);
        }
      }, 0);
    });
  });
}

// 调用示例
checkPopupBlocked('你的目标跳转地址').then(isPopupAllowed => {
  alert(isPopupAllowed ? 'enabled' : 'blocked');
});

核心调整点:

  • 把同步判断改成异步检测:Chrome对缓存权限下的弹窗拦截是异步执行的,返回引用后几百毫秒才会真正关闭窗口,同步读取属性拿不到准确状态
  • 增加100ms间隔的短轮询,最多检测2.5秒:同时校验窗口的closed状态、内部属性可访问性,区分正常打开的弹窗(含跨域弹窗)和被拦截的弹窗
  • 区分跨域报错和拦截报错:正常打开的跨域弹窗访问内部location会触发跨域安全错误,但窗口不会被自动关闭;被拦截的弹窗会在短时间内被Chrome自动关闭,结合这个特征可以准确识别拦截状态
  • 增加定时器清理逻辑,避免内存泄漏,同时兼容用户手动快速关闭窗口的极端场景

注意:所有弹窗检测逻辑必须在用户主动交互事件(如click、touchstart)的同步调用栈中触发,Chrome对非用户交互触发的弹窗默认全局拦截,不存在可绕过的检测方案。

内容的提问来源于stack exchange,提问作者sbh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:51:14