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

如何识别特定事件的源JS文件?解决document.open事件丢失问题

识别事件监听器的源脚本文件,解决document.open后的事件复用问题

你遇到的核心痛点是没法动态判断addEventListener调用来自哪个脚本文件,之前硬编码的方式显然不够灵活。这里有个可靠的方案,利用JavaScript的调用栈(Error.stack)来提取当前执行代码的源文件信息,完美适配你的需求:

步骤1:添加脚本文件检测辅助函数

首先写一个工具函数,通过创建Error对象读取调用栈,解析出当前执行代码所在的脚本文件名。这个方法兼容绝大多数现代浏览器:

function getCurrentScriptFileName() {
  try {
    throw new Error();
  } catch (e) {
    // 拆分调用栈行,跳过当前函数和addEventListener自身的调用记录
    const stackLines = e.stack.split('\n');
    const targetLine = stackLines.find(line => 
      !line.includes('getCurrentScriptFileName') && !line.includes('addEventListener')
    );
    if (!targetLine) return '';
    
    // 适配不同浏览器的栈格式,提取文件名
    const urlMatch = targetLine.match(/(https?:\/\/|file:\/\/).*?(\/[^\/]+?\.js)(?::\d+)?/i);
    const fileNameMatch = targetLine.match(/([^\/]+?\.js)(?::\d+)?/i);
    return urlMatch ? urlMatch[2].split('/').pop() : fileNameMatch ? fileNameMatch[1] : '';
  }
}

步骤2:修改addEventListener逻辑,动态检测源文件

把你代码里硬编码的isFromSourceX替换成调用上述函数的结果,就能自动识别事件监听器是否来自你的目标脚本:

(function(self) {
  // 初始化全局存储数组(防止重复初始化)
  if (!window._stackedListeners) {
    window._stackedListeners = [];
  }

  function getCurrentScriptFileName() {
    try {
      throw new Error();
    } catch (e) {
      const stackLines = e.stack.split('\n');
      const targetLine = stackLines.find(line => 
        !line.includes('getCurrentScriptFileName') && !line.includes('addEventListener')
      );
      if (!targetLine) return '';
      
      const urlMatch = targetLine.match(/(https?:\/\/|file:\/\/).*?(\/[^\/]+?\.js)(?::\d+)?/i);
      const fileNameMatch = targetLine.match(/([^\/]+?\.js)(?::\d+)?/i);
      return urlMatch ? urlMatch[2].split('/').pop() : fileNameMatch ? fileNameMatch[1] : '';
    }
  }

  EventTarget.prototype.addEventListenerBase = EventTarget.prototype.addEventListener;
  EventTarget.prototype.addEventListener = function(type, listener, params) {
    // 动态获取当前调用者的脚本文件名
    const currentScript = getCurrentScriptFileName();
    const isFromSourceX = currentScript === 'nameoffile.js';

    const worker_events = ['DOMContentLoaded', 'beforeunload', "blue","devicemotion","deviceorientation", "error","focus","load","message","orientationchange", "resize","scroll","storage","click"];
    const _this = this;
    // 用some()优化事件存在性判断,比filter()[0]更高效
    const _isEventExists = window._stackedListeners.some(item => item.type === type && item.target === _this);
    const isHtmlElement = this instanceof HTMLElement;

    if (worker_events.includes(type) && !_isEventExists && isFromSourceX) {
      window._stackedListeners.push({ target: _this, type: type, listener: listener, params: params });
      this.addEventListenerBase(type, listener, params);
    }
  };
})(self);

关键细节说明

  • 调用栈解析逻辑:通过抛出临时Error获取调用栈,跳过当前工具函数和addEventListener自身的调用行,精准定位到触发事件绑定的代码所在脚本。
  • 兼容性处理:适配Chrome、Firefox等不同浏览器的调用栈格式,不管是本地file://路径还是远程HTTPS路径,都能正确提取文件名。
  • 性能优化:将原来的filter()[0]替换为some(),判断事件是否存在时会提前终止遍历,提升代码效率。

修改后,你就能自动识别来自nameoffile.js的事件监听器,后续document.open执行后,直接遍历window._stackedListeners数组重新绑定事件即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 00:17:51