使用jQuery列出页面上所有已绑定的JavaScript事件

46
使用jQuery,是否可以获得所有事件及其绑定的元素列表?

请查看<a href="http://stackoverflow.com/questions/675120/inspect-javascript-calls-for-gmails-buttons/677924#677924">这个问题</a>和<a href="https://dev59.com/_EbRa4cB1Zd3GeqP5f7K">另一个</a>。 - cllpse
现在已经消失.data('events')。请访问http://bugs.jquery.com/ticket/10589。 - Skylar Saveland
谢谢,@SkylarSaveland,我正在更新我的答案。 - Prestaul
5个回答

95

jQuery使这相对容易,因为它将事件处理程序存储在元素数据中。您应该能够使用类似这样的代码:

(function($) {
    $.eventReport = function(selector, root) {
        var s = [];
        $(selector || '*', root).andSelf().each(function() {
            // the following line is the only change
            var e = $.data(this, 'events');
            if(!e) return;
            s.push(this.tagName);
            if(this.id) s.push('#', this.id);
            if(this.className) s.push('.', this.className.replace(/ +/g, '.'));
            for(var p in e) {
                var r = e[p],
                    h = r.length - r.delegateCount;
                if(h)
                    s.push('\n', h, ' ', p, ' handler', h > 1 ? 's' : '');
                if(r.delegateCount) {
                    for(var q = 0; q < r.length; q++)
                        if(r[q].selector) s.push('\n', p, ' for ', r[q].selector);
                }
            }
            s.push('\n\n');
        });
        return s.join('');
    }
    $.fn.eventReport = function(selector) {
        return $.eventReport(selector, this);
    }
})(jQuery);

你可以这样调用它:

// all events
alert($.eventReport());

// just events on inputs
alert($.eventReport('input')); 

// just events assigned to this element
alert($.eventReport('#myelement')); 

// events assigned to inputs in this element
alert($.eventReport('input', '#myelement')); 
alert($('#myelement').eventReport('input')); // same result

// just events assigned to this element's children
alert($('#myelement').eventReport()); 
alert($.eventReport('*', '#myelement'); // same result

更新: 我添加了一个处理程序的计数,并在上述函数的输出中提供了有关委托事件的一些信息。

更新(2012年8月24日): 虽然上述函数仍适用于jQuery 1.7.2及更低版本,但jQuery不再将事件对象存储在jQuery.data(elem, 'events')中。 如果您正在使用jQuery 1.8或更高版本,则无法再使用上述函数!

作为对jQuery.data(elem, 'events')的替换,您现在可以使用jQuery._data(elem, 'events')。 更新后的函数如下:

(function($) {
    $.eventReport = function(selector, root) {
        var s = [];
        $(selector || '*', root).addBack().each(function() {
            // the following line is the only change
            var e = $._data(this, 'events');
            if(!e) return;
            s.push(this.tagName);
            if(this.id) s.push('#', this.id);
            if(this.className) s.push('.', this.className.replace(/ +/g, '.'));
            for(var p in e) {
                var r = e[p],
                    h = r.length - r.delegateCount;
                if(h)
                    s.push('\n', h, ' ', p, ' handler', h > 1 ? 's' : '');
                if(r.delegateCount) {
                    for(var q = 0; q < r.length; q++)
                        if(r[q].selector) s.push('\n', p, ' for ', r[q].selector);
                }
            }
            s.push('\n\n');
        });
        return s.join('');
    }
    $.fn.eventReport = function(selector) {
        return $.eventReport(selector, this);
    }
})(jQuery);

更新(2013年4月25日):从1.8.x版本开始,andSelf()已停用,请使用addBack()代替。详情请参见http://bugs.jquery.com/ticket/9800


3
更新了jQuery 1.8修复和一些额外的输出,用于处理程序计数和委托事件。 - Prestaul
1
答案不包括文档或窗口上的事件,仅供参考,但您可以通过执行$.eventReport(document)和$.eventReport(window)来获取它们。 - mattwad
2
我似乎每隔几年就会回到这个工具,而且它仍然有效。拥有这样一个绝妙的工具真是太棒了。 - basicdays
这将成为我超酷且有用的脚本收藏之一。 - alexandernst
能否编辑 var r = e[p] 数组?我问这个问题是因为它看起来不像一个“正常”的数组,而更像是其它类型的本地对象。 - alexandernst
1
@alexandernst,它不是一个数组,而是一个对象。你可以修改它,尽管我建议你小心谨慎地操作... 它是jQuery内部的一部分,用于管理事件。 - Prestaul

5
// List bound events
console.log($('#elem').data('events'));

// Log ALL handlers for ALL events
$.each($('#elem').data('events'), function(i, event) {
  $.each(event, function(i, handler){
    console.log(handler.toString());
  });
});

3

我使用这个功能来列出所有具有限定事件的元素。

$('*').each(function(){
    var events = $(this).data('events');
    if(events != null)
    {
        console.log(this);
        console.log(events);
    }
});

通过编写一些额外的代码,也可以将每个事件的元素收集为列表,例如:

var eventArrays = {};

$('*').each(function(){
    var events = $(this).data('events');
    for(var anEvent in events){
        if(!eventArrays[anEvent])
            eventArrays[anEvent] = [];
        eventArrays[anEvent].push(this);
    }
});

console.log(eventArrays);

0
为了使用console.table(),我做了一些修改...
(function($) {
    $.eventReport = function(selector, root) {
        var s = [];
        $(selector || '*', root).addBack().each(function() {
            var e = $._data(this, 'events');
            if(!e) return;
            var tagGroup = this.tagName || "document";
            if(this.id) tagGroup += '#' + this.id;
            if(this.className) tagGroup += '.' + this.className.replace(/ +/g, '.');

            var delegates = [];
            for(var p in e) {
                var r = e[p];
                var h = r.length - r.delegateCount;

                if(h)
                    s.push([tagGroup, p + ' handler' + (h > 1 ? 's' : '')]);

                if(r.delegateCount) {
                    for(var q = 0; q < r.length; q++)
                        if(r[q].selector) s.push([tagGroup + ' delegates', p + ' for ' + r[q].selector]);
                }
            }
        });
        return s;
    }
    $.fn.eventReport = function(selector) {
        return $.eventReport(selector, this);
    }
})(jQuery);

现在我可以做这样的事情:

console.table($.eventReport())

在 Chrome 中看看会发生什么: Chrome 中的控制台


0

我敢打赌,你可以遍历DOM并检查每个元素上的事件属性,从而建立一个列表...但我从未尝试过。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接