是否可以以编程方式捕获浏览器中页面上的所有事件?

Šim*_*das 49 javascript browser events dom

首先,这里是W3C标准定义的事件类型列表.(此列表基于HTML5标准中定义的onevent属性.我假设有许多其他事件类型,但此列表足够长.)

  • 退出
  • 打印后
  • beforeprint
  • beforeunload
  • 模糊
  • 可以玩
  • canplaythrough
  • 更改
  • 点击
  • 上下文菜单
  • 复制
  • cuechange
  • DBLCLICK
  • DOMContentLoaded
  • 拖动
  • dragend
  • 的dragenter
  • dragleave
  • 的dragover
  • 的dragstart
  • 下降
  • durationchange
  • 清空
  • 结束
  • 错误
  • 焦点
  • 专注于
  • 事件的内容
  • formchange
  • 的formInput
  • hashchange
  • 输入
  • 无效
  • KEYDOWN
  • 按键
  • KEYUP
  • 加载
  • loadeddata
  • 等待loadedmetadata
  • loadstart
  • 信息
  • 鼠标按下
  • 的mouseenter
  • 鼠标离开
  • 鼠标移动
  • 鼠标移开
  • 鼠标移到
  • 鼠标松开
  • 鼠标滚轮
  • 离线
  • 线上
  • pagehide
  • pageshow
  • 暂停
  • 播放
  • popstate
  • 进展
  • ratechange
  • readystatechange
  • 重做
  • 重启
  • 调整
  • 滚动
  • seeked
  • 选择
  • 节目
  • 停滞
  • 存储
  • 提交
  • 暂停
  • timeupdate
  • 解开
  • 卸下
  • volumechange
  • 等候

现在,是否可以定义在页面上任何元素上最初发生任何事件时调用的全局事件处理程序?(在这种情况下,我不想计算元素上发生的事件,因为它们从后代元素冒出来 - 这就是我写"最初发生"的原因.)

如果这是不可能的,至少可以定义一个事件处理程序,当任何事件冒泡到DOM树的根(它是document对象或window对象 - 两者都应该工作)时调用它?(我知道可以以编程方式停止冒泡,但我会在没有其他任何元素上定义的其他处理程序的页面上使用此事件处理程序.)(另外,我相信某些事件不会冒泡,但让我们忽略这些为了这个论点的例子.)

我知道我可以这样做(使用jQuery):

$(document).bind('abort afterprint beforeprint beforeunload etc.', function() {
    // handle event
});
Run Code Online (Sandbox Code Playgroud)

但这对我来说是一个相当不理想的解决方案.

顺便说一句我不需要跨浏览器的解决方案.如果只在一个浏览器中工作,我很好.

此外,Firebug能够记录事件,但我希望能够以编程方式(通过JavaScript)捕获事件,而不是让它们只是登录控制台.

Vla*_*sla 20

/*

function getAllEventTypes(){

  if(location.href !='https://developer.mozilla.org/en-US/docs/Web/Events') return;

  var types = {};
  $('.standard-table:eq(0) tr').find('td:eq(1)').map(function(){
    var type = $.trim(this.innerText) || 'OtherEvent';
    types[type] = types[type] || [];     
    var event = $.trim(this.previousElementSibling.innerText);
    if(event) types[type].push(event);
  });
  for(var t in types) types[t] = types[t].join(' ');
  return "var DOMEvents = "+JSON.stringify(types, null, 4).replace(/"(\w+)\":/ig, '$1:');
}

*/

var DOMEvents = {
UIEvent: "abort DOMActivate error load resize scroll select unload",
ProgressEvent: "abort error load loadend loadstart progress progress timeout",
Event: "abort afterprint beforeprint cached canplay canplaythrough change chargingchange chargingtimechange checking close dischargingtimechange DOMContentLoaded downloading durationchange emptied ended ended error error error error fullscreenchange fullscreenerror input invalid languagechange levelchange loadeddata loadedmetadata noupdate obsolete offline online open open orientationchange pause pointerlockchange pointerlockerror play playing ratechange readystatechange reset seeked seeking stalled submit success suspend timeupdate updateready visibilitychange volumechange waiting",
AnimationEvent: "animationend animationiteration animationstart",
AudioProcessingEvent: "audioprocess",
BeforeUnloadEvent: "beforeunload",
TimeEvent: "beginEvent endEvent repeatEvent",
OtherEvent: "blocked complete upgradeneeded versionchange",
FocusEvent: "blur DOMFocusIn  Unimplemented DOMFocusOut  Unimplemented focus focusin focusout",
MouseEvent: "click contextmenu dblclick mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup show",
SensorEvent: "compassneedscalibration Unimplemented userproximity",
OfflineAudioCompletionEvent: "complete",
CompositionEvent: "compositionend compositionstart compositionupdate",
ClipboardEvent: "copy cut paste",
DeviceLightEvent: "devicelight",
DeviceMotionEvent: "devicemotion",
DeviceOrientationEvent: "deviceorientation",
DeviceProximityEvent: "deviceproximity",
MutationNameEvent: "DOMAttributeNameChanged DOMElementNameChanged",
MutationEvent: "DOMAttrModified DOMCharacterDataModified DOMNodeInserted DOMNodeInsertedIntoDocument DOMNodeRemoved DOMNodeRemovedFromDocument DOMSubtreeModified",
DragEvent: "drag dragend dragenter dragleave dragover dragstart drop",
GamepadEvent: "gamepadconnected gamepaddisconnected",
HashChangeEvent: "hashchange",
KeyboardEvent: "keydown keypress keyup",
MessageEvent: "message message message message",
PageTransitionEvent: "pagehide pageshow",
PopStateEvent: "popstate",
StorageEvent: "storage",
SVGEvent: "SVGAbort SVGError SVGLoad SVGResize SVGScroll SVGUnload",
SVGZoomEvent: "SVGZoom",
TouchEvent: "touchcancel touchend touchenter touchleave touchmove touchstart",
TransitionEvent: "transitionend",
WheelEvent: "wheel"
}

var RecentlyLoggedDOMEventTypes = {};

for(DOMEvent in DOMEvents){

  var DOMEventTypes = DOMEvents[DOMEvent].split(' ');

  DOMEventTypes.filter(function(DOMEventType){
    var DOMEventCategory = DOMEvent + ' '+DOMEventType;  
    document.addEventListener(DOMEventType, function(e){
      if(RecentlyLoggedDOMEventTypes[DOMEventCategory]) return;
      RecentlyLoggedDOMEventTypes[DOMEventCategory] = true;
      setTimeout(function(){ RecentlyLoggedDOMEventTypes[DOMEventCategory] = false }, 5000);
      var isActive = e.target==document.activeElement;
      if(isActive) {
        console.info(DOMEventCategory, 
          ' target=', e.target, 
          ' active=', document.activeElement, 
          ' isActive=', true );
      } else {
        console.log(DOMEventCategory, 
          ' target=', e.target,
          ' active=', document.activeElement, 
          ' isActive=', false );
      }

    }, true);
  });

}
Run Code Online (Sandbox Code Playgroud)


小智 9

您可以遍历dom元素的所有属性并选择与/on(.*)/ pattern匹配的属性(例如onclick或onmousemove):

var events = [];
for (var property in element) {
    var match = property.match(/^on(.*)/)
    if (match) { 
        events.push(match[1]);
    }
}
console.log(events.join(' '))
Run Code Online (Sandbox Code Playgroud)


pit*_*zle 6

如何监听特定目标上的所有事件Element

\n
\n

对于所有本机事件target.onevent,我们可以通过迭代属性并为所有事件安装侦听器来检索支持的事件列表。

\n
for (const key in target) {\n    if(/^on/.test(key)) {\n        const eventType = key.substr(2);\n        target.addEventListener(eventType, listener);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

据我所知,发出事件的唯一其他方式是 via EventTarget.dispatchEvent,其中 everyNode和fore everyElement继承。
\n要侦听所有这些手动触发的事件,我们可以dispatchEvent全局代理该方法,并为我们刚刚看到其名称的事件及时安装侦听器 \xe2\x9c\xa8 ^^

\n
const dispatchEvent_original = EventTarget.prototype.dispatchEvent;\nEventTarget.prototype.dispatchEvent = function (event) {\n    if (!alreadyListenedEventTypes.has(event.type)) {\n        target.addEventListener(event.type, listener, ...otherArguments);\n        alreadyListenedEventTypes.add(event.type);\n    }\n    dispatchEvent_original.apply(this, arguments);\n};\n
Run Code Online (Sandbox Code Playgroud)\n
\n

函数片段

\n
function addEventListenerAll(target, listener, ...otherArguments) {\n\n    // install listeners for all natively triggered events\n    for (const key in target) {\n        if (/^on/.test(key)) {\n            const eventType = key.substr(2);\n            target.addEventListener(eventType, listener, ...otherArguments);\n        }\n    }\n\n    // dynamically install listeners for all manually triggered events, just-in-time before they\'re dispatched ;D\n    const dispatchEvent_original = EventTarget.prototype.dispatchEvent;\n    function dispatchEvent(event) {\n        target.addEventListener(event.type, listener, ...otherArguments);  // multiple identical listeners are automatically discarded\n        dispatchEvent_original.apply(this, arguments);\n    }\n    EventTarget.prototype.dispatchEvent = dispatchEvent;\n    if (EventTarget.prototype.dispatchEvent !== dispatchEvent) throw new Error(`Browser is smarter than you think!`);\n\n}\n\n\n// usage example\naddEventListenerAll(window, (evt) => {\n    console.log(evt.type);\n});\ndocument.body.click();\ndocument.body.dispatchEvent(new Event(\'omg!\', { bubbles: true }));\n\n\n// usage example with `useCapture`\n// (also receives `bubbles: false` events, but in reverse order)\naddEventListenerAll(\n    window,\n    (evt) => { console.log(evt.type); },\n    true\n);\ndocument.body.dispatchEvent(new Event(\'omfggg!\', { bubbles: false }));\n
Run Code Online (Sandbox Code Playgroud)\n


use*_*621 5

我非常怀疑在Firefox中有一种方法可以做到这一点.看看Firebug的源代码(特别是attachAllListeners方法),结果显示迭代事件名称列表显然是要走的路,但这并不能解决冒泡问题.


jos*_*c89 3

似乎没有任何“简单的方法”可以做到这一点。

我的想法:你知道哪些是所有事件,因此你可以处理每个 DOM 元素的所有事件:

var events =
[   
    "onabort",
    "onafterprint",
    "onbeforeprint",
    "onbeforeunload",
    ...

];

var root = document.body;
var elms = root.childNodes;

for(var i = 0; i < elms.length; i++)
{
    for(var j = 0; j < events.length; j++)
    {
        elms[i][events[j]] = globalHandler;
    }
}

function globalHandler()
{
    alert("Global handler called");
}
Run Code Online (Sandbox Code Playgroud)

这是“直观的想法”,但似乎效率不高。然而,它应该有效。

祝你好运。

  • @Sime 只要确保你只有几个元素就可以了! (4认同)
  • 我认为将每种可能的事件类型的事件处理程序分配给页面上的每个可能的元素并不是一个好主意。我担心我的浏览器会爆炸`:)` (3认同)