ChatGPT解决这个技术问题 Extra ChatGPT

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

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

例如:

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

$("#el") 已注册 clickmouseover

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

如果通过适当的方法在 jQuery 对象上是不可能的,那么在普通的 DOM 对象上是否可能?

不幸的是,现在:bugs.jquery.com/ticket/10589
支持 jQuery pre 和 post 1.8:var events = (jQuery._data || jQuery.data)(elem, 'events');
请注意,您可以使用 FF 和 Chrome 开发工具(F12)来查看这些事件侦听器。请参阅 developers.google.com/web/tools/chrome-devtools/debug/…developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/…

g
gnarf

从 jQuery 1.8 开始,事件数据不再可从“公共 API”获取数据。阅读this jQuery blog post。您现在应该改用它:

jQuery._data( elem, "events" );

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

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

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

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

但您仍然可以使用 $._data($(elem).get(0), "events")
blog.jquery.com/2011/11/08/building-a-slimmer-jquery .data(“events”):jQuery 将其与事件相关的数据存储在一个名为(等待它)每个元素上的事件的数据对象中。这是一个内部数据结构,因此在 1.8 中这将从用户数据名称空间中删除,因此它不会与同名项目冲突。 jQuery 的事件数据仍然可以通过 jQuery._data(element, "events") 访问,但请注意这是一个未记录的内部数据结构,不应修改。
无缝支持这两个选项:var events = (jQuery._data || jQuery.data)(elem, 'events');
@CrazyMerlin 好的,谢谢。现在也许你有更好的答案?
它返回未定义。
N
Nick Craver

您可以通过抓取事件(从 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); }); }); });函数输出(文本) { $("#output").html(函数(i, h) { return h + text + "
"; }); }

测试


适用于 1.4,但不适用于 jQuery 1.8.2。
对于 jQuery 1.8+,您必须使用“私有数据”方法:jQuery._data( jQuery("#el")[0], "events" ); 而不是“公共数据”方法:jQuery("#el").data("events")events 对象实际上已经很久没有存储在 .data() 中了,我们通过从“公共 API”中删除这个“代理”来修剪掉几个字节的代码
P
PhistucK

对于 jQuery 1.8+,这将不再起作用,因为内部数据被放置在不同的对象中。

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

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


$._data("body", "events") 未定义 $().jquery; “1.7.1”(一直尝试 1.7.2 和 1.8.1 “未定义”)
@Michal - api.jquery.com/jQuery.data 说它接受一个元素,而不是一个选择器。
现在工作正常: $._data($("body").get(0), "events") 甚至更好: $("body").data("events") !
FWIW - 指出它“内部”使用我们特别没有记录的参数调用其他数据函数可能不需要。但是,是的,jQuery._data( element, "events" ) 是现在获取此信息的“正确”方式。
R
Rui

无耻的插件,但你可以使用findHandlerJS

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

对于您的示例,您可以通过执行快速找到您提到的事件处理程序

findEventHandlers("click", "#el")
findEventHandlers("mouseover", "#el")

这是返回的内容:

element 注册事件处理程序的实际元素

events 包含我们感兴趣的事件类型的 jquery 事件处理程序信息的数组(例如单击、更改等) handler 实际的事件处理程序方法,您可以通过右键单击它并选择 Show function definition selector 为委托提供的选择器事件。对于直接事件,它将为空。包含此事件处理程序所针对的元素的列表。例如,对于在文档对象中注册并针对页面中所有按钮的委托事件处理程序,此属性将列出页面中的所有按钮。您可以将它们悬停并查看它们以 chrome 突出显示。

handler 实际的事件处理程序方法,您可以通过右键单击它并选择显示函数定义来查看

选择器 为委托事件提供的选择器。对于直接事件,它将为空。

包含此事件处理程序所针对的元素的列表。例如,对于在文档对象中注册并针对页面中所有按钮的委托事件处理程序,此属性将列出页面中的所有按钮。您可以将它们悬停并查看它们以 chrome 突出显示。

你可以试试here


A
Anton

为此,我使用 eventbug 插件来触发萤火虫。


谢谢,很好的提示。该扩展向 Firebug(“事件”)添加了一个选项卡,显示页面的事件,因此您可以轻松地对它们进行扩展。
此外,Chrome 开发者工具在“元素”选项卡下有“事件监听器”,在“源”选项卡下有“事件监听器断点”。
a
algorhythm

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

jQuery.fn.getEvents = function() {
    if (typeof(jQuery._data) === 'function') {
        return jQuery._data(this.get(0), 'events') || {};
    }

    // jQuery version < 1.7.?
    if (typeof(this.data) === 'function') {
        return this.data('events') || {};
    }

    return {};
};

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


T
Tom G

要检查元素上的事件:

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])

这个 getEvents 方法总体上很棒,但问题是,它在 IE11 中提供了重复的条目(我知道,IE 再次,但公司需要它......)。编辑:$._data 包含元素的重复事件,即使在 FF 上它不包含任何...奇怪的 IE 世界。但重要的是要注意这种重复事件的可能性。
哦,汤姆,实际上是您的代码在每次执行此方法时都会增加事件。不好。
o
oligofren

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

来自 .data("events") 上的 jQuery 文档

在 1.9 之前,如果没有其他代码定义了名为“events”的数据元素,则可以使用 .data("events") 为元素检索 jQuery 未记录的内部事件数据结构。这种特殊情况已在 1.9 中删除。没有公共接口来检索这个内部数据结构,并且它仍然没有记录。但是,jQuery Migrate 插件为依赖它的代码恢复了这种行为。


接受的答案还清楚地显示了获取最新版本的新的正确方法:jQuery._data( elem, "events" );...
私人的、无证的方式永远不会是正确的方式。正确的方法——即记录的、公开的和预期的——是使用 Migrate 插件。
您似乎误解了 Migrate 插件的意义。 jQuery 删除了不推荐使用的功能,而 Migrate 插件旨在帮助将开发人员的代码迁移到较新的版本,以便他们可以立即利用新功能和改进,但不会丢失功能。它旨在帮助编码人员了解他们需要做什么才能正确开始使用新版本的 jQuery。您不应该在生产中使用它来恢复功能。此外,jQuery 文档中没有记录和更新许多内容 - 他们之前已经指出过,所以这不是原因
此外,如果它作为 jQuery 博客中的建议包含在内,我会使用它:blog.jquery.com/2012/08/09/jquery-1-8-released
您对 Migrate 插件的推理似乎是合理的。如果我删除我的答案,好吗?
E
Erutan409

我创建了一个自定义 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)")

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


J
Jesan Fafon

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

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

在您的浏览器控制台中,它将打印处理程序的来源,以逗号分隔。对于查看特定事件的所有运行情况很有用。


jQuery._data('ct100_ContentPlaceHolder1_lcsSection','events')["EVENT_NAME"].map(function(elem){return elem.handler;}); 未捕获的类型错误:无法在 <anonymous>:1:62 读取未定义的属性“EVENT_NAME”
'ct100_ContentPlaceHolder1_lcsSection' 是字符串,而不是 DOM 元素。
R
R. Oosterholt

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

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

或 jQuery 1.8+:

jQuery._data(elem, 'events');

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

jQuery(document).data('events')

jQuery(document).data('events') 给了我未定义的
D
Dominik Szymański

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;
}

p
pid

不得不说很多答案都很有趣,但是最近我也遇到了类似的问题,通过走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;
      }
    }
  });
}

M
Marquinho Peli

如果您使用的是 chrome,请尝试 jquery 调试器插件:https://chrome.google.com/webstore/detail/jquery-debugger/dbhhnnnpaeobfddmlalhnehgclcmjimi?hl=en


t
tempranova

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

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

我认为 jQuery 会进行事件处理优化,我认为您的代码在此处绕过了该优化。
谢谢,是的,我觉得这很hacky-有什么好的链接可以了解有关该优化的更多信息吗?
M
Marek Lisý

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

var element = $("#some-element"); // 示例事件处理程序 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 (事件,函数(i,事件){如果(!事件)返回;$.each(事件,函数(j,h){var found = false;如果(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); } }); }); });