【问题标题】:Get event listeners attached to node using addEventListener使用 addEventListener 获取附加到节点的事件侦听器
【发布时间】:2012-02-21 05:39:47
【问题描述】:

我已经看过这些问题了:

但是他们都没有回答如何使用addEventListener 获取附加到节点的事件侦听器列表,而无需在创建事件侦听器之前修改addEventListener 原型。

VisualEvent 不显示所有事件侦听器(特定于 iPhone 的事件),我想(在某种程度上)以编程方式执行此操作。

【问题讨论】:

标签: javascript dom-events


【解决方案1】:

由于没有本地方法可以做到这一点,这是我找到的侵入性较小的解决方案(不要添加任何“旧”原型方法):

var ListenerTracker=new function(){
    var targets=[];
    // listener tracking datas
    var _elements_  =[];
    var _listeners_ =[];
    this.init=function(){
        this.listen(Element,window);
    };
    this.listen=function(){
        for(var i=0;i<arguments.length;i++){
            if(targets.indexOf(arguments[i])===-1){
                targets.push(arguments[i]);//avoid duplicate call
                intercep_events_listeners(arguments[i]);
            }
        }
    };
    // register individual element an returns its corresponding listeners
    var register_element=function(element){
        if(_elements_.indexOf(element)==-1){
            // NB : split by useCapture to make listener easier to find when removing
            var elt_listeners=[{/*useCapture=false*/},{/*useCapture=true*/}];
            _elements_.push(element);
            _listeners_.push(elt_listeners);
        }
        return _listeners_[_elements_.indexOf(element)];
    };
    var intercep_events_listeners = function(target){
        var _target=target;
        if(target.prototype)_target=target.prototype;
        if(_target.getEventListeners)return;
        if(typeof(_target.addEventListener)!=='function'||typeof(_target.removeEventListener)!=='function'){
            console.log('target=',target);
            throw('\nListenerTracker Error:\nUnwrappable target.');
        }
        // backup overrided methods
        var _super_={
            "addEventListener"      : _target.addEventListener,
            "removeEventListener"   : _target.removeEventListener
        };

        _target["addEventListener"]=function(type, listener, useCapture){
            var listeners=register_element(this);
            // add event before to avoid registering if an error is thrown
            _super_["addEventListener"].apply(this,arguments);
            // adapt to 'elt_listeners' index
            var uc=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
            if(!listeners[uc][type])listeners[uc][type]=[];
            listeners[uc][type].push({cb:listener,args:arguments});
        };
        _target["removeEventListener"]=function(type, listener, useCapture){
            var listeners=register_element(this);
            // add event before to avoid registering if an error is thrown
            _super_["removeEventListener"].apply(this,arguments);
            // adapt to 'elt_listeners' index
            useCapture=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
            if(!listeners[useCapture][type])return;
            var lid = listeners[useCapture][type].findIndex(obj=>obj.cb===listener);
            if(lid>-1)listeners[useCapture][type].splice(lid,1);
        };
        _target["getEventListeners"]=function(type){
            var listeners=register_element(this);
            // convert to listener datas list
            var result=[];
            for(var useCapture=0,list;list=listeners[useCapture];useCapture++){
                if(typeof(type)=="string"){// filtered by type
                    if(list[type]){
                        for(var id in list[type]){
                            result.push({
                                "type":type,
                                "listener":list[type][id].cb,
                                "args":list[type][id].args,
                                "useCapture":!!useCapture
                            });
                        }
                    }
                }else{// all
                    for(var _type in list){
                        for(var id in list[_type]){
                            result.push({
                                "type":_type,
                                "listener":list[_type][id].cb,
                                "args":list[_type][id].args,
                                "useCapture":!!useCapture
                            });
                        }
                    }
                }
            }
            return result;
        };
    };

}();


ListenerTracker.init();

编辑

来自@mplungjan 的建议:修改为收听可包装目标(单例|构造函数)。 'init' 跟踪 元素窗口

以其他可包装目标为例:

ListenerTracker.listen(XMLHttpRequest);

来自@kodfire 的建议:您可以通过 args 属性获得可选参数。

【讨论】:

  • 你也应该让它拦截窗口事件监听器。除此之外,这很好用!
  • 可以用类似的脚本拦截window.addEventListener吗?
  • window 对象是一个单例,不继承自 Element。如果要拦截 window.addEventListener,则必须复制此代码并将 Element.prototypeHTMLElement.prototype 替换为 窗口.
  • 真棒 :)) 是否可以在 javascript 中而不是在 devtools 中调用 getEventListeners
  • @kodfire 谢谢。跟踪器在全局范围内重载 HTMLElement 事件方法。所以一旦你调用了ListenerTracker.init();,每个新事件都会被堆叠,你可以从任何脚本调用element.getEventListeners();
【解决方案2】:

你不能。

获取附加到节点的所有事件侦听器列表的唯一方法是拦截侦听器附件调用。

DOM4 addEventListener

将事件侦听器附加到关联的事件侦听器列表,其中类型设置为类型、侦听器设置为侦听器、捕获设置为捕获,除非该列表中已经存在具有相同类型、侦听器和捕获的事件侦听器.

表示将事件侦听器添加到“事件侦听器列表”中。就这样。不知道该列表应该是什么,也不知道您应该如何访问它。

【讨论】:

  • 能否提供一些理由或理由说明为什么它必须以这种方式工作?很明显,浏览器知道所有的监听器是什么。
  • @user973810:你希望他如何证明这一点? DOM API 无法做到这一点,并且在当前的浏览器中也没有非标准的方法来做到这一点。至于为什么会这样,我真的不知道。这似乎是一件合情合理的事情。
  • 我已经看到一些关于为此向 DOM 添加 API 的线程。
  • @TimDown 编辑帮助。看到没有像“getEventListeners”这样的规范说明为什么没有这样的东西。
  • 我发现它对 Electron 应用程序或 Chrome 扩展程序之类的东西很有用。一些事件监听器可能被注入到页面中,但是远程页面没有任何线索——这很好。
【解决方案3】:

Chrome DevTools、Safari Inspector 和 Firebug 支持 getEventListeners(node)

【讨论】:

  • 我要注意 getEventListeners 方法不支持 Firefox 35 版本。
  • 它可能无法在 Firefox 上运行,但随后开发人员再次在多个浏览器上开发/如果需要修改现有站点,这肯定会有所帮助......很多!
  • 不是 Firefox 69。
【解决方案4】:

我找不到使用代码执行此操作的方法,但在现有的 Firefox 64 中,事件列在开发人员工具检查器中的每个 HTML 实体旁边,如 MDN 的 Examine Event Listeners 页面上所述,如下图所示:

【讨论】:

    【解决方案5】:

    您可以使用 $._data($('[selector]')[0],'events'); 获取所有 jQuery 事件将 [选择器] 更改为您需要的。

    有一个插件可以收集 jQuery 附加的所有事件,称为 eventsReport。

    我还编写了自己的插件,以更好的格式做到这一点。

    但无论如何,我们似乎无法收集 addEventListener 方法添加的事件。也许我们可以包装 addEventListener 调用来存储在我们的 wrap 调用之后添加的事件。

    这似乎是使用开发工具查看添加到元素的事件的最佳方式。

    但是你不会在那里看到委托事件。所以我们需要jQuery eventsReport。

    更新:现在我们可以看到 addEventListener 方法添加的事件,请参阅此问题的正确答案。

    【讨论】:

    • 这是一个私有且已弃用的接口,它可能很快就会消失,所以不要依赖它。
    • 是的,但是我回答的时候,开发工具中没有这样的能力。所以,没有什么可以选择的。
    • 不推荐使用@Rantiev,您可以删除该答案吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多