jQuery查找使用对象注册的事件处理程序

时间:2010-03-25 18:47:08

标签: jquery events dom

我需要找到在对象上注册的事件处理程序。

例如:

$("#el").click(function() {...});
$("#el").mouseover(function() {...});

$("#el") 点击鼠标悬停已注册。

是否有一个函数可以找出它,并可能迭代事件处理程序?

如果通过适当的方法在jQuery对象上无法实现,是否可以在普通的DOM对象上进行?

16 个答案:

答案 0 :(得分:652)

从jQuery 1.8开始,数据的“公共API”不再提供事件数据。阅读this jQuery blog post。你现在应该使用它:

jQuery._data( elem, "events" );

elem应该是HTML元素,而不是jQuery对象或选择器。

请注意,这是一个内部的“私人”结构,不应修改。仅用于调试目的。

在旧版本的jQuery中,您可能必须使用旧方法:

jQuery( elem ).data( "events" );

答案 1 :(得分:77)

你可以通过抓取事件(从jQuery 1.8+开始)来实现,如下所示:

$.each($._data($("#id")[0], "events"), function(i, event) {
  // i is the event type, like "click"
  $.each(event, function(j, h) {
    // h.handler is the function being called
  });
});

以下是您可以使用的示例:

$(function() {
  $("#el").click(function(){ alert("click"); });
  $("#el").mouseover(function(){ alert("mouseover"); });

  $.each($._data($("#el")[0], "events"), function(i, event) {
    output(i);
    $.each(event, function(j, h) {
        output("- " + h.handler);
    });
  });
});

function output(text) {
    $("#output").html(function(i, h) {
        return h + text + "<br />";
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="el">Test</div>
<code>
    <span id="output"></span>
</code>

答案 2 :(得分:35)

对于jQuery 1.8+,这将不再有效,因为内部数据放在不同的对象中。

最新的非官方(但在以前的版本中也适用,至少在1.7.2中)现在这样做的方式是 - $._data(element, "events")

下划线(“_”)就是这里的不同之处。在内部,它调用$.data(element, name, null, true),最后一个(第四个)参数是内部参数(“pvt”)。

答案 3 :(得分:32)

无耻插件,但您可以使用findHandlerJS

要使用它,您只需要包含findHandlersJS(或只是将raw javascript code复制并粘贴到Chrome的控制台窗口),并为您感兴趣的元素指定事件类型和jquery选择器。

对于您的示例,您可以通过执行

快速找到您提到的事件处理程序
findEventHandlers("click", "#el")
findEventHandlers("mouseover", "#el")

这是返回的内容:

  • 元素
  • 中注册事件处理程序的实际元素
  • 事件
    包含有关我们感兴趣的事件类型的jquery事件处理程序的信息的数组(例如,单击,更改等)
    • 处理程序
      通过右键单击并选择显示函数定义
    • 可以看到的实际事件处理程序方法
    • 选择
      选择器为委派事件提供。对于直接活动,它将是空的。
    • 目标
      列出此事件处理程序所针对的元素。例如,对于在文档对象中注册并指向页面中所有按钮的委托事件处理程序,此属性将列出页面中的所有按钮。您可以悬停它们并在Chrome中突出显示它们。

您可以尝试here

答案 4 :(得分:12)

我为此目的使用eventbug插件来进行骚扰。

答案 5 :(得分:8)

我已将@jps的两个解决方案合并到一个功能中:

jQuery.fn.getEvents = function() {
    if (typeof(jQuery._data) == 'function') {
        return jQuery._data(this.get(0), 'events') || {};
    } else if (typeof(this.data) == 'function') { // jQuery version < 1.7.?
        return this.data('events') || {};
    }
    return {};
};

但请注意,此函数只能返回使用jQuery本身设置的事件。

答案 6 :(得分:5)

从1.9开始,除了使用Migrate插件恢复旧行为之外,没有记录的方法来检索事件。你可以使用_.data()方法作为jps提及,但这是一个内部方法。因此,如果您需要此功能,请做正确的事情并使用Migrate插件。

来自.data("events")

上的jQuery文档
  

在1.9之前,.data(“events”)可用于检索jQuery   没有其他元素的未记录的内部事件数据结构   代码定义了一个名为“events”的数据元素。这个特别的   案件已于1.9删除。没有要检索的公共接口   这个内部数据结构,它仍然没有记录。然而,   jQuery Migrate插件为依赖的代码恢复此行为   在它上面。

答案 7 :(得分:3)

我创建了一个自定义jQuery选择器,它检查指定事件处理程序的jQuery缓存以及使用本机方法添加它们的元素:

(function($){

    $.find.selectors[":"].event = function(el, pos, match) {

        var search = (function(str){
            if (str.substring(0,2) === "on") {str = str.substring(2);}
            return str;
        })(String(match[3]).trim().toLowerCase());

        if (search) {
            var events = $._data(el, "events");
            return ((events && events.hasOwnProperty(search)) || el["on"+search]);
        }

        return false;

    };

})(jQuery);

示例:

$(":event(click)")

这将返回附加了点击处理程序的元素。

答案 8 :(得分:2)

在具有ECMAScript 5.1 / Array.prototype.map的现代浏览器中,您还可以使用

jQuery._data(DOCUMENTELEMENT,'events')["EVENT_NAME"].map(function(elem){return elem.handler;});

在浏览器控制台中,它将打印处理程序的源代码,以逗号分隔。用于浏览特定事件的所有内容。

答案 9 :(得分:2)

要检查元素上的事件:

var events = $._data(element, "events")
  

请注意,这仅适用于直接事件处理程序,如果您使用$(document).on(“ event-name”,“ jq-selector”,function(){// logic}),则需要看到答案底部的getEvents函数

例如:

 var events = $._data(document.getElementById("myElemId"), "events")

 var events = $._data($("#myElemId")[0], "events")

完整示例:

<html>
    <head>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript"></script>
        <script>
            $(function() {
                $("#textDiv").click(function() {
                    //Event Handling
                });
                var events = $._data(document.getElementById('textDiv'), "events");
                var hasEvents = (events != null);
            });
        </script>
    </head>
    <body>
        <div id="textDiv">Text</div>
    </body>
</html>

一种更完整的检查方法,其中包括在$(document).on上安装的动态侦听器。

function getEvents(element) {
    var elemEvents = $._data(element, "events");
    var allDocEvnts = $._data(document, "events");
    for(var evntType in allDocEvnts) {
        if(allDocEvnts.hasOwnProperty(evntType)) {
            var evts = allDocEvnts[evntType];
            for(var i = 0; i < evts.length; i++) {
                if($(element).is(evts[i].selector)) {
                    if(elemEvents == null) {
                        elemEvents = {};
                    }
                    if(!elemEvents.hasOwnProperty(evntType)) {
                        elemEvents[evntType] = [];
                    }
                    elemEvents[evntType].push(evts[i]);
                }
            }
        }
    }
    return elemEvents;
}

用法示例:

getEvents($('#myElemId')[0])

答案 10 :(得分:1)

可以使用以下方法检索事件:

jQuery(elem).data('events');

或jQuery 1.8 +:

jQuery._data(elem, 'events');

注意: 使用$('selector').live('event', handler)限制的事件 可以使用以下方法检索:

jQuery(document).data('events')

答案 11 :(得分:1)

我不得不说很多答案很有意思,但最近我遇到了类似的问题,并且通过DOM方式解决方案非常简单。这是不同的,因为你不会迭代,但直接针对你需要的事件,但在下面我会给出一个更一般的答案。

我连续拍了一张照片:

<table>
  <td><tr><img class="folder" /></tr><tr>...</tr></td>
</table>

该图像附加了一个点击事件处理程序:

imageNode.click(function () { ... });

我的目的是将可点击区域扩展到整行,所以我首先得到所有图像和相对行:

tableNode.find("img.folder").each(function () {
  var tr;

  tr = $(this).closest("tr");
  // <-- actual answer
});

现在在实际的anwer 行中,我刚刚做了如下,给出了原始问题的答案:

tr.click(this.onclick);

所以我直接从DOM元素中获取了事件处理程序并将其放入jQuery click事件处理程序中。像魅力一样。

现在,就一般情况而言。在旧的jQuery之前的日子里,你可以通过 Douglas Crockford 向我们凡人赠送两个简单但功能强大的函数,将所有事件附加到一个对象上:

function walkTheDOM(node, func)
{
  func(node);
  node = node.firstChild;
  while (node)
  {
    walkTheDOM(node, func);
    node = node.nextSibling;
  }
}

function purgeEventHandlers(node)
{
  walkTheDOM(node, function (n) {
    var f;

    for (f in n)
    {
      if (typeof n[f] === "function")
      {
        n[f] = null;
      }
    }
  });
}

答案 12 :(得分:1)

如果您使用chrome:https://chrome.google.com/webstore/detail/jquery-debugger/dbhhnnnpaeobfddmlalhnehgclcmjimi?hl=en

,请尝试使用jquery调试器插件

答案 13 :(得分:1)

jQuery不允许您仅访问给定元素的事件。 您可以使用未公开的内部方法

访问它们
$._data(element, "events")

但是它仍然不会为您提供所有事件,确切地说,不会向您显示分配给

的事件
$([selector|element]).on()

这些事件存储在文档中,因此您可以通过浏览

来获取它们
$._data(document, "events")

但这是艰苦的工作,因为整个网页都有事件。

Tom G在上面创建的函数中仅过滤给定元素的事件的文档并合并这两种方法的输出,但是它具有在输出中复制事件的缺陷(并有效地在元素的jQuery内部事件列表上与应用程序混淆) 。 我已修复该缺陷,您可以在下面找到代码。只需将其粘贴到开发控制台或应用程序代码中,然后在需要时执行它即可获得给定元素的所有事件的详细列表。

需要注意的是,元素实际上是HTMLElement,而不是jQuery对象。

function getEvents(element) {
    var elemEvents = $._data(element, "events");
    var allDocEvnts = $._data(document, "events");
    function equalEvents(evt1, evt2)
    {
        return evt1.guid === evt2.guid;
    }

    for(var evntType in allDocEvnts) {
        if(allDocEvnts.hasOwnProperty(evntType)) {
            var evts = allDocEvnts[evntType];
            for(var i = 0; i < evts.length; i++) {
                if($(element).is(evts[i].selector)) {
                    if(elemEvents == null) {
                        elemEvents = {};
                    }
                    if(!elemEvents.hasOwnProperty(evntType)) {
                        elemEvents[evntType] = [];
                    }
                    if(!elemEvents[evntType].some(function(evt) { return equalEvents(evt, evts[i]); })) {
                        elemEvents[evntType].push(evts[i]);
                    }
                }
            }
        }
    }
    return elemEvents;
}

答案 14 :(得分:0)

另一种方法是使用jQuery来获取元素,然后通过实际的Javascript来获取和设置并使用事件处理程序。例如:

var oldEventHandler = $('#element')[0].onclick;
// Remove event handler
$('#element')[0].onclick = null;
// Switch it back
$('#element')[0].onclick = oldEventHandler;

答案 15 :(得分:0)

我结合了上面的一些答案,并创建了一个看上去疯狂但功能强大的脚本,该脚本希望列出给定元素上的大多数事件侦听器。随时在这里对其进行优化。

var element = $("#some-element");

// sample event handlers
element.on("mouseover", function () {
  alert("foo");
});

$(".parent-element").on("mousedown", "span", function () {
  alert("bar");
});

$(document).on("click", "span", function () {
  alert("xyz");
});

var collection = element.parents()
  .add(element)
  .add($(document));
collection.each(function() {
  var currentEl = $(this) ? $(this) : $(document);
  var tagName = $(this)[0].tagName ? $(this)[0].tagName : "DOCUMENT";
  var events = $._data($(this)[0], "events");
  var isItself = $(this)[0] === element[0]
  if (!events) return;
  $.each(events, function(i, event) {
    if (!event) return;
    $.each(event, function(j, h) {
      var found = false;        
      if (h.selector && h.selector.length > 0) {
        currentEl.find(h.selector).each(function () {
          if ($(this)[0] === element[0]) {
            found = true;
          }
        });
      } else if (!h.selector && isItself) {
        found = true;
      }

      if (found) {
        console.log("################ " + tagName);
        console.log("event: " + i);
        console.log("selector: '" + h.selector + "'");
        console.log(h.handler);
      }
    });
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="parent-element">
  <span id="some-element"></span>
</div>