有没有办法用Javascript找到元素的事件处理程序?

问题描述 投票:0回答:5

假设你有这个div:

<div id="foo">bar</div>

你这样做:

$("#foo").click(someFunction);

Javascript 代码中的某个地方。

页面加载后,有没有办法通过 Firebug 或 Chrome 中的检查元素或其他任何方式找出

#foo
的点击事件是否绑定到
someFunction
?即,无需查看所有代码即可找到这一点?

javascript jquery debugging event-handling dom-events
5个回答
16
投票

Chrome 开发者工具可以做到这一点。

  1. 右键单击一个元素
  2. 单击检查元素
  3. 在右侧栏中,向下滚动到事件侦听器

这将为您提供对象上的事件侦听器列表,可以扩展该列表以查找其源和附加函数。

Firebug 在 DOM 选项卡下有此信息,但用户不太友好。


7
投票

您可以在浏览器内置开发者工具中使用控制台。它们是内置的 IE 和 Chrome,而 FF 则需要安装 Firebug AddOn。我不知道其他浏览器。

使用调试器控制台,您可以使用 jQuery

data("events")
查询元素的附加事件。此外,这些控制台还可以让您动态深入了解您感兴趣的事件的任何其他细节。

$("#foo").data("events");

在控制台中执行上述命令将显示一个对象,其中包含找到的每个事件的属性。在您的示例中,它返回一个具有

click
属性的对象,其类型为存储所有单击事件的数组。

如果您有单击事件并且您只需要该对象,您可以在控制台中执行以下操作:

$("#foo").data("events").click;

每个事件对象都有一个

handler
属性,它将向您显示它们绑定到的函数:

Object
data: null
guid: 2
handler: function mytestFunction(){
arguments: null
caller: null
guid: 2
length: 0
name: "mytestFunction"
prototype: mytestFunction
__proto__: function Empty() {}
namespace: ""
origType: "click"
quick: null
selector: null
type: "click"
__proto__: Object

参见DEMO,展示如何在控制台中查询和显示对象。

或者,您也可以使用“处理程序”作为整体摘要对象:

$("#foo").data("handlers");

请注意,

.data("events/handlers")
不会包含嵌入在 html 中的任何事件,如下所示:

<div id="foo" onclick="...">bar</div>

有关

data()
的更多信息位于 文档


3
投票

我不了解 Firefox,但有一种简单的方法可以在 Chrome 和 Safari 中查看事件侦听器。只需打开开发人员工具,选择您的元素并滚动到 CSS 属性面板的底部。您会找到“事件侦听器”部分。


2
投票

我建议使用

Visual Event 2

这里是关于如何使用它的描述。我几乎每天都使用它,它是一个非常好的工具。


0
投票

是的,这是可能的,你甚至可以在纯JS中做到这一点,但前提是你用自己的拦截器拦截/覆盖addEventListener和removeEventListener原型函数,这样你就可以拦截它们。

这适用于使用 addEventListener 添加的任何内容(并且它考虑了 removeEventListener)。

但是如果您在没有 EventListener 的情况下添加它们,例如使用 element.onclick (或在标记中的 onclick/onAnything-attribute 中),这不会列出它们,您必须手动检查它们。

确保以下 JavaScript 是您页面上执行的第一个脚本,否则可能无法正常工作。

方法如下(TypeScript):

type EventHandlerMapType = {
    // [key: EventTarget]: { [type: string]: EventListenerOrEventListenerObject[] };
    [key: string]: { [type: string]: EventListenerOrEventListenerObject[] };
};


type EventHandlerMapValue = { [type: string]: EventListenerOrEventListenerObject[] };
interface EventTarget
{
    getEventHandlers: (type?: string) => EventHandlerMapValue | EventListenerOrEventListenerObject[];
}





// function addEventListener<K extends keyof ElementEventMap>(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, options ?: boolean | AddEventListenerOptions): void;
// addEventListener(type: string, listener: EventListenerOrEventListenerObject, options ?: boolean | AddEventListenerOptions): void;


(function ()
{
    // Store the handlers by element reference
    // WeakMap can take an object, such as an Element, as a key, object cannot. 
    // This is useful because WeakMap allows for garbage collection of the keys(the elements), 
    // meaning when an Element is removed from the DOM and no longer referenced, it gets garbage - collected, 
    // and its entry in the WeakMap is automatically removed. 
    // This prevents memory leaks.
    const eventHandlerMap = new WeakMap<EventTarget>(); // Dictionary<Element, { type:[]}> // where type is string and array is an array of handlers/listeners

    // Override the native addEventListener
    const originalAddEventListener = EventTarget.prototype.addEventListener;

    
    
    EventTarget.prototype.addEventListener = function (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions)
    {
        // Call the original addEventListener to ensure normal behavior
        originalAddEventListener.call(this, type, listener, options);

        // Initialize tracking for the current element if it doesn't exist
        if (!eventHandlerMap.has(this))
        {
            eventHandlerMap.set(this, {});
        }

        // Get the event type handlers for this element
        const handlersForElement = eventHandlerMap.get(this);
        if (!handlersForElement[type])
        {
            handlersForElement[type] = [];
        }

        // Add the handler to the list for this event type
        handlersForElement[type].push(listener);
    };

    // Override the native removeEventListener
    const originalRemoveEventListener = EventTarget.prototype.removeEventListener;
    EventTarget.prototype.removeEventListener = function (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions)
    {
        // Call the original removeEventListener to ensure normal behavior
        originalRemoveEventListener.call(this, type, listener, options);

        // Remove the handler from the tracking list
        if (eventHandlerMap.has(this))
        {
            const handlersForElement = eventHandlerMap.get(this);
            if (handlersForElement[type])
            {
                // Filter out the handler that matches the one being removed
                handlersForElement[type] = handlersForElement[type].filter((h: EventListenerOrEventListenerObject) => h !== listener);

                // Clean up if no handlers left for this event type
                if (handlersForElement[type].length === 0)
                {
                    delete handlersForElement[type];
                }
            }

            // Clean up the element if no handlers left for any event type
            if (Object.keys(handlersForElement).length === 0)
            {
                eventHandlerMap.delete(this);
            }
        }
    };

    // Function to retrieve all event handlers for an element
    EventTarget.prototype.getEventHandlers = function (type?: string): EventHandlerMapValue | EventListenerOrEventListenerObject[]
    {
        // Get the tracking list for the current element
        const handlersForElement = eventHandlerMap.get(this) || {};

        if (type)
        {
            // If a specific event type is requested, return its handlers
            return handlersForElement[type] || [];
        }

        // If no type is specified, return all handlers grouped by type
        return handlersForElement;
    };

})();

现在在 EventTarget(元素、节点等)上:

getEventHandlers(type?: string)

或者用普通的 JS

(function () {
    var eventHandlerMap = new WeakMap();
    var originalAddEventListener = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function (type, listener, options) {
        originalAddEventListener.call(this, type, listener, options);
        if (!eventHandlerMap.has(this)) {
            eventHandlerMap.set(this, {});
        }
        var handlersForElement = eventHandlerMap.get(this);
        if (!handlersForElement[type]) {
            handlersForElement[type] = [];
        }
        handlersForElement[type].push(listener);
    };
    var originalRemoveEventListener = EventTarget.prototype.removeEventListener;
    EventTarget.prototype.removeEventListener = function (type, listener, options) {
        originalRemoveEventListener.call(this, type, listener, options);
        if (eventHandlerMap.has(this)) {
            var handlersForElement = eventHandlerMap.get(this);
            if (handlersForElement[type]) {
                handlersForElement[type] = handlersForElement[type].filter(function (h) { return h !== listener; });
                if (handlersForElement[type].length === 0) {
                    delete handlersForElement[type];
                }
            }
            if (Object.keys(handlersForElement).length === 0) {
                eventHandlerMap.delete(this);
            }
        }
    };
    EventTarget.prototype.getEventHandlers = function (type) {
        var handlersForElement = eventHandlerMap.get(this) || {};
        if (type) {
            return handlersForElement[type] || [];
        }
        return handlersForElement;
    };
})();

测试:

var btnCreated = document.createElement("button");
btnCreated.textContent = "Hello Kitty";
btnCreated.value = "Hello Kitty";
document.body.appendChild(btnCreated);
var btn = document.querySelector('button');
function handleClick() {
    console.log('Button clicked');
}
btn.addEventListener('click', handleClick);
btn.addEventListener('clock', handleClick);
console.log(btn.getEventHandlers('click'));
console.log("before click");
btn.click();
console.log("after click");
btn.removeEventListener('click', handleClick);
console.log("before click after click removed");
btn.click();
console.log("after click after click removed");
console.log("click handlers", btn.getEventHandlers('click'));
console.log("all handlers", btn.getEventHandlers());
© www.soinside.com 2019 - 2024. All rights reserved.