如何在 javascript 中为所有事件添加事件侦听器而不单独列出它们?
Posted
技术标签:
【中文标题】如何在 javascript 中为所有事件添加事件侦听器而不单独列出它们?【英文标题】:How can I add an event listener for all events in javascript without listing them individually? 【发布时间】:2017-02-19 04:54:03 【问题描述】:我想使用通配符完成以下代码(我认为不存在?)
myObject.element = document.getElementsByClassName('js-myObject');
myObject.element.addEventListener('click', myObject.click);
myObject.element.addEventListener('mouseover', myObject.mouseover);
//etc..
到目前为止,我有以下内容
myObject.controller = function(e)
if( (e.type in myObject) && (typeof myObject[e.type] ==='function') )
myObject[e.type](e);
;
//but the listeners still have to be assigned as such
myObject.element = document.getElementsByClassName('js-myObject');
myObject.element.addEventListener('click', myObject.controller);
myObject.element.addEventListener('mouseover', myObject.controller);
//etc...
// but I want to do (and it doesn't work)
myObject.element.addEventListener('*', myObject.controller);
对于事件数组和 foreach 语句以外的方法有什么建议吗?
编辑,我目前的解决方案
我接受了下面的答案(没有可用的通配符,解析可能数百个事件是个坏主意)
对于那些寻找类似功能的人,我已经确定了以下方法,至少目前是这样。
for(var prop in myObject)
if (!myObject.hasOwnProperty(prop)continue;
if (typeof myObject[prop] !== 'function')continue;
myObject.element.addEventListener(prop, myObject[prop]);
好处是我不必返回并为其添加侦听器的自定义事件的处理程序。缺点是我必须确保在定义每个 myObject.someEvent() 之后调用此函数。我在 myObject.init(); 中调用它这对我来说很好。请注意,此解决方案不符合我以前的规范,因为它使用 for/each 循环——但它完成了我真正想要完成的工作,非常感谢@torazaburo 明确定义了我的技术限制和缺乏智慧初步计划。
【问题讨论】:
把你的对象放在一个数组中,并在一个循环中设置处理程序 或使用 jquery,它会这样做 ***.com/questions/7439570/… @Pamblam 请理解我正在寻找一种方法来避免列出每个事件。 我强烈怀疑您想为所有事件添加监听器。['click', 'mouseover'].forEach(evt => myObject.element.addEventListener(evt, myObject.controller));
怎么了?
【参考方案1】:
没有通配符,但使用 jQuery,您可以拥有 1 个长事件侦听器行,而不是多个。
How do you log all events fired by an element in jQuery?
像这样:
('body').on("click mousedown mouseup focus blur keydown change dblclick mousemove mouseover mouseout mousewheel keydown keyup keypress textInput touchstart touchmove touchend touchcancel resize scroll zoom select change submit reset",function(e)
console.log(e);
);
【讨论】:
这是一个很好的资源——感谢 mmcrae,但仍然不是我想要的。即,它不处理自定义事件。我想知道javascript是否不允许我正在寻找的东西。 (另外,如果它不是一个完整的解决方案,我宁愿不需要 jquery) 不处理自定义事件是什么意思?然后只需将其添加到click mycustomevent mousedown
的字符串中?
我无法编辑关于不处理自定义事件的评论。但是您必须手动添加每个自定义事件。同样,我正在寻找通配符类型的解决方案
似乎是一个奇怪的要求,将某些东西绑定到每一个可能的事件......但是 idk。无论如何,谷歌搜索 jquery wildcard event
会导致您可能应该查看的内容,例如 ***.com/questions/9735608/…
缺少输入,粘贴【参考方案2】:
聚会有点晚了,但这是我添加所有事件侦听器并将它们记录到控制台的方法:
Object.keys(window).forEach(key =>
if(/./.test(key))
window.addEventListener(key.slice(2), event =>
console.log(key, event)
)
)
【讨论】:
测试不应该是/^on/
吗? (以“开”开头)
@SamHasler 你是对的。已经有一段时间了,但我相信我在某个时候将它与事件发射器一起使用,所以我只是删除了那部分。
我刚刚注意到的一件有趣的事情:即使没有 /^on/,它似乎也不会为 GamePad 事件触发...【参考方案3】:
没有添加*
侦听器的功能,我怀疑您是否希望在一个元素上监听数百个事件。
顺便说一句,您应该使用涉及EventListener
接口和handleEvent
方法的被低估的方法,而不是以myObject.controller
的形式为通用事件处理程序创建自己的架构它定义了。
【讨论】:
@torazabura -- 谢谢。这被接受为答案,因为当其他人试图解决它时,他们不符合我的标准。 1. 没有 foreach,2. 所有事件 这在 chrome 中不起作用。我使用document.body.addEventListener('*', function(e) console.log('event', e); );
尝试过它在 chrome 或 firefox 中不起作用。起作用的是个别事件。不起作用的是多个事件。
@MrMesees 如果您阅读了整个评论,您会注意到上面的代码实际上是 user663031 引用了 OP。
那么他们应该使用一种机制来显示,比如blockquote和cite【参考方案4】:
如何自己实现addEventListener('*')
对于所有本机事件,我们可以通过遍历 target.onevent
属性并为所有事件安装我们的侦听器来检索支持的事件列表。
for (const key in target)
if(/^on/.test(key))
const eventType = key.substr(2);
target.addEventListener(eventType, listener);
据我所知,发出事件的唯一另一种方式是通过EventTarget.dispatchEvent
,每个Node
和因此每个Element
都继承。
要监听所有这些手动触发的事件,我们可以全局代理dispatchEvent
方法,并为我们刚刚看到的名称的事件安装我们的监听器✨ ^^
const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
EventTarget.prototype.dispatchEvent = function (event)
if (!alreadyListenedEventTypes.has(event.type))
target.addEventListener(event.type, listener, ...otherArguments);
alreadyListenedEventTypes.add(event.type);
dispatchEvent_original.apply(this, arguments);
;
? 函数 sn-p ?
function addEventListenerAll(target, listener, ...otherArguments)
// install listeners for all natively triggered events
for (const key in target)
if (/^on/.test(key))
const eventType = key.substr(2);
target.addEventListener(eventType, listener, ...otherArguments);
// dynamically install listeners for all manually triggered events, just-in-time before they're dispatched ;D
const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
function dispatchEvent(event)
target.addEventListener(event.type, listener, ...otherArguments); // multiple identical listeners are automatically discarded
dispatchEvent_original.apply(this, arguments);
EventTarget.prototype.dispatchEvent = dispatchEvent;
if (EventTarget.prototype.dispatchEvent !== dispatchEvent) throw new Error(`Browser is smarter than you think!`);
// usage example
function addEventListenerAll(target, listener, ...otherArguments)
// install listeners for all natively triggered events
for (const key in target)
if (/^on/.test(key))
const eventType = key.substr(2);
target.addEventListener(eventType, listener, ...otherArguments);
// dynamically install listeners for all manually triggered events, just-in-time before they're dispatched ;D
const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
function dispatchEvent(event)
target.addEventListener(event.type, listener, ...otherArguments); // multiple identical listeners are automatically discarded
dispatchEvent_original.apply(this, arguments);
EventTarget.prototype.dispatchEvent = dispatchEvent;
if (EventTarget.prototype.dispatchEvent !== dispatchEvent) throw new Error(`Browser is smarter than you think!`);
// usage example
addEventListenerAll(window, (evt) =>
console.log(evt.type);
);
document.body.click();
document.body.dispatchEvent(new Event('omg!', bubbles: true ));
// usage example with `useCapture`
// (also receives `bubbles: false` events, but in reverse order)
addEventListenerAll(
window,
(evt) => console.log(evt.type); ,
true
);
document.body.dispatchEvent(new Event('omfggg!', bubbles: false ));
【讨论】:
【参考方案5】:如果这就是你要找的东西,我不是 100%,但我认为这就是你要找的东西。
document
是我们通常为我们的事件标记的不包含事件。它实际上是祖父母类。
document -> htmlDocument -> Document (where you could find the onclick* events)
如您所见,我们可以这样做。只需在事件开始时修剪 on
Object.keys(document.__proto__.__proto__).reduce((arr, event)=>
if(event.startsWith('on')) return [...arr, event.substr(2)];
return arr;
, [])
这将返回类似:
["readystatechange", "pointerlockchange", "pointerlockerror", "beforecopy", "beforecut", "beforepaste", "freeze", "resume", "search", "securitypolicyviolation", "visibilitychange", "copy", "cut", "paste", "abort", "blur", "cancel", "canplay", "canplaythrough", "change", "click", "close", "contextmenu", "cuechange", "dblclick", "drag", "dragend", "dragenter", "dragleave", "dragover", "dragstart", "drop", "durationchange", "emptied", "ended", "error", "focus", "formdata", "input", "invalid", "keydown", "keypress", "keyup", "load", "loadeddata", "loadedmetadata", "loadstart", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "mousewheel", "pause", "play", "playing", "progress", "ratechange", "reset", "resize", "scroll", "seeked", "seeking", "select", "stalled", "submit", "suspend", "timeupdate", "toggle", "volumechange", "waiting", "webkitanimationend", "webkitanimationiteration", "webkitanimationstart", "webkittransitionend", "wheel", "auxclick", "gotpointercapture", "lostpointercapture", "pointerdown", "pointermove", "pointerup", "pointercancel", "pointerover", "pointerout", "pointerenter", "pointerleave", "selectstart", "selectionchange", "animationend", "animationiteration", "animationstart", "transitionend", "fullscreenchange", "fullscreenerror", "webkitfullscreenchange", "webkitfullscreenerror", "pointerrawupdate"]
这只是我想出的快速方法,我相信更聪明的人会提供更好的答案。您可能还想查看https://developer.mozilla.org/en-US/docs/Web/Events,其中包含您可能需要的内容。
【讨论】:
不错的解决方案,虽然我更喜欢 filter-map 来减少:.filter((prop) => prop.startsWith('on')).map((prop) => prop.substr(2))
【参考方案6】:
getElementsByClassName
已经返回一个数组(或者更具体地说,一个HTMLCollection
),而不是单个元素。循环执行即可。
myObject.element = document.getElementsByClassName('js-myObject');
for(var i=0; i<myObject.element.length; i++)
myObject.element[i].addEventListener('click', myObject.controller);
myObject.element[i].addEventListener('mouseover', myObject.controller);
编辑...澄清后..循环和数组仍然有用
var e = ['click', 'hover', 'focus', 'mouseover', 'mouseout'];
myObject.element = document.getElementsByClassName('js-myObject');
for(var i=0; i<myObject.element.length; i++)
for(var n=0; n<e.length; n++)
myObject.element[i].addEventListener(e[n], myObject.controller);
【讨论】:
我相信你错过了我的问题的重点。这不是为多个对象添加相同的侦听器。它是将所有侦听器添加到单个对象而不列出每个事件侦听器 他说的是向一个元素添加许多事件,而不是向许多元素添加事件 @pamblam 感谢更新——但我确实在问题中指定了我不想要数组和 foreach 循环。例如,该解决方案不会处理自定义事件 如果您将自定义事件添加到循环中,它将考虑它们。不幸的是,我认为这是你最好的选择。【参考方案7】:查找页面上的所有事件监听器
getEventListeners(document)
Reference
把它们列出得更好一点
for (const [key, value] of Object.entries(getEventListeners(document)))
console.log(`$key`)
我会留给你来实际做一些事情,但是现在你至少可以看到页面上存在的所有内容,你可以打开 DevTools 并在这个页面上尝试一下,你自己看看它确实有效。
【讨论】:
复制粘贴到 DevTools 中的代码以查看此页面有您可以列出的侦听器【参考方案8】:这样的?
document.addEventListener('click', function (event)
if (event.target.closest('.scroll'))
// Do something...
if (event.target.matches('[data-some-attribute]'))
// Do something else...
if (event.target.matches('#my-form'))
// Do another t hing...
, false)
【讨论】:
以上是关于如何在 javascript 中为所有事件添加事件侦听器而不单独列出它们?的主要内容,如果未能解决你的问题,请参考以下文章
点击事件后:如何通过 javascript 向 URL 添加内容?
试图在JavaScript / jQuery中添加一个on click事件