如何找出Chrome扩展程序中特定HTML元素附加的事件侦听器类型?

Mic*_*tor 5 chromium google-chrome-extension

我在这里发布这个问题,因为我无法在官方的Chromium扩展论坛上发布它(或者在它被审核之前有一个非常大的延迟).我必须检查Chromium扩展是否有一个特定事件类型的监听器附加到任意HTML元素.在Firefox中,我可以使用以下服务来获取此信息:

var listenerService = Components.classes["@mozilla.org/eventlistenerservice;1"]
            .getService(Components.interfaces.nsIEventListenerService);
var infos = listenerService.getListenerInfoFor(element, {});
var types = [];
for ( var i = 0; i < infos.length; ++i) {
  var info = infos[i].QueryInterface(Components.interfaces.nsIEventListenerInfo);
  types.push(info.type);
}
Run Code Online (Sandbox Code Playgroud)

正如我在Chromium中看到的,没有类似的API.因此,我尝试了以下技术(这里建议):

我创建了脚本events_spy.js:

(function(original) {
  Element.prototype.addEventListener = function(type, listener, useCapture) {
    if (typeof (this._handlerTypes) == 'undefined') {
      this._handlerTypes = {};
    }
    this._handlerTypes[type] = true;
    return original.apply(this, arguments);
  }
})(Element.prototype.addEventListener);

(function(original) {
  Element.prototype.removeEventListener = function(type, listener,useCapture) {
    if (typeof (this._handlerTypes) != 'undefined') {
      delete this._handlerTypes[type];
    }
    return original.apply(this, arguments);
  }
})(Element.prototype.removeEventListener);
Run Code Online (Sandbox Code Playgroud)

我将此脚本声明manifest.json如下:

"content_scripts" : [{
  "matches" : [ "http://*/*", "https://*/*" ],
  "js" : [ "content/events_spy.js" ],
  "run_at" : "document_start",
  "all_frames" : true
},
...
]
Run Code Online (Sandbox Code Playgroud)

然后,我在以下HTML页面上测试我的扩展:

<!DOCTYPE html>
<html>
 <head>
 </head>
 <body>
  <a id="test" href="#">Click here</a>
  <script type="application/javascript">
       document.getElementById("test").addEventListener("click", function()
{ alert("clicked"); }, false);
  </script>
 </body>
</html>
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用 - 我看不到调试器在我的自定义addEventListener()函数内停止.我究竟做错了什么?

谢谢!

编辑:最终(脏)解决方案,感谢@kdzwinel

var injectedJS = "\
(function(original) { \
  Element.prototype.addEventListener = function(type, listener, useCapture) { \
    var attr = this.getAttribute('_handlerTypes'); \
    var types = attr ? attr.split(',') : []; \
    var found = false; \
    for (var i = 0; i < types.length; ++i) { \
      if (types[i] == type) { \
        found = true; \         
        break; \                
      } \               
    } \         
    if (!found) { \
      types.push(type); \
    } \         
    this.setAttribute('_handlerTypes', types.join(',')); \
    return original.apply(this, arguments); \
  } \   
})(Element.prototype.addEventListener); \
\
(function(original) { \
  Element.prototype.removeEventListener = function(type, listener, useCapture) { \
    var attr = this.getAttribute('_handlerTypes'); \
    var types = attr ? attr.split(',') : []; \
    var removed = false; \
    for (var i = 0; i < types.length; ++i) { \
      if (types[i] == type) { \
        types.splice(i, 1); \   
        removed = true; \       
        break; \                
      } \               
    } \         
    if (removed) { \
      this.setAttribute('_handlerTypes', types.join(',')); \
    } \         
    return original.apply(this, arguments); \
  } \   
})(Element.prototype.removeEventListener); \
";

var script = document.createElement("script");
script.type = "text/javascript";
script.appendChild(document.createTextNode(injectedJS));
document.documentElement.appendChild(script);
Run Code Online (Sandbox Code Playgroud)

每个具有附加事件侦听器的HTML元素都将具有特殊属性"_handlerTypes",其中包含以逗号分隔的事件列表.此扩展程序的内容脚本可以访问此属性!

Kon*_*nel 1

当我在单个独立的 HTML 文件上测试您的脚本时,它运行良好。但由于以下政策,它不能作为 Chrome 扩展程序运行:

内容脚本在称为隔离世界的特殊环境中执行。它们可以访问所注入页面的 DOM,但不能访问该页面创建的任何 JavaScript 变量或函数。它看起来每个内容脚本都好像没有其他 JavaScript 在其运行的页面上执行。反之亦然:页面上运行的 JavaScript 无法调用任何函数或访问内容脚本定义的任何变量。 [来源]

为了安全并避免冲突,所有内容都经过沙箱处理。页面和内容脚本之间的所有通信都必须通过 DOM 处理。


看来有人遇到了与您相同的问题并使其工作:

我通过让我的内容脚本将一个元素附加到页面中来解决这个问题,该脚本查找 DOM 元素并使用 jQuery 的 $(node).data("events") 获取其事件侦听器。它通过使用适当的数据向自身添加属性来与我的扩展进行通信。显然,这仅适用于使用 jQuery API 附加事件处理程序的页面,但由于这是我所使用的所有内容,因此这是我可以忍受的限制。可怕的黑客。我会假装我从来没有写过它。如果您有兴趣:github.com/grantyb/Google-Chrome-Link-URL-Extension [来源]

如果您设法使用您的events_spy.js而不是$(node).data("events"). 此外,他在页面和内容脚本之间进行通信的方式也很丑陋。使用文档中描述的解决方案(“与嵌入页面的通信”部分)。