有没有办法覆盖浏览器或用户代理的事件调度?

is there a way to override event dispatch from browser or user agent?

我想要的是,当一个元素接收到一个事件时,我希望它首先做“某事”,这个“某事”可能是评估是否调用注册的事件监听器。

我可以通过调用 .dispatchEvent(event) 方法来覆盖手动调度事件,但不能通过浏览器调用事件 sent/dispatch,例如用户点击按钮。

这是我的尝试:

let evtDispatcher = EventTarget.prototype.dispatchEvent;
let foo = false;
EventTarget.prototype.dispatchEvent = function(evt) {
  if (foo) {
    console.log('Event Sent');
    evtDispatcher.call(this, evt);
  } else {
    console.log('No Event Sent');
  }
}

function displayMe(evt) {
  document.getElementById('span-id').innerHTML = 'Clicked';
}

let bttn = document.getElementById('bttn-id');

bttn.addEventListener('click', displayMe);
//When user click the "button" tag
// Desire result: don't call the event listener and log "No Event Sent" on console
// Actual result: event listener is called and "Event Sent" is log on console

bttn.dispatchEvent(new Event('click')); 
//manual dispatch works

Here's my attempt code on JsFiddle

答案是“有时”。

我不建议尝试覆盖 dispatchEvent() 或任何其他本机方法,因为它对很多事情都不起作用。许多事件处理的事情发生在您可以使用 JavaScript.

访问的级别以下

相反,您可以尝试使用 event capture.

来实现它

如果您将 true 提供给事件的 useCapture 参数或 capture 选项,您基本上会赋予该元素优先于其他未使用捕获的元素。如果您在 htmlbody 在 top-level 执行此操作,他们将有机会根据任意逻辑查看并可能 stopPropagation() 事件你要。

你可以通过这个小样本看到这种情况。

const allow = document.querySelector('input');
const div = document.querySelector('div');
const span = document.querySelector('span');
const button = document.querySelector('button');

div.addEventListener('click', event => {
  console.log('div');
  
  if (!allow.checked) {
    event.stopPropagation();
  }
}, { capture: true });

span.addEventListener('click', () => console.log('span'));
button.addEventListener('click', () => console.log('p'));
<label>Allow through? <input type="checkbox"></label>
<div>
  <span>
    <button>Click Me</button>
  </span>
</div>

所以,如果你对每一个可能的事件都这样做,你通常可以做你想做的。但是也有一些例外,因此上面的“有时”,定义不是非常明确,并且由浏览器完成以试图防止欺诈和黑客攻击等等。我不知道有没有关于您不能覆盖的地方的完整列表,但如果您真的不需要每个事件都这样做,那可能并不重要。

也没有通配符事件,因此您必须将它连接到每个事件,但有一些方法可以实现 .

最后一点,因为你提到了用户代理。如果您出于任何安全目的而尝试这样做:请不要这样做。或者,至少,确保您在 back-end 上仍然拥有完整的保护。 front-end 上的任何“安全性”都只是安全区,无论实施得多么好,都可以轻易地被知识渊博的人绕过。