有没有办法覆盖浏览器或用户代理的事件调度?
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
答案是“有时”。
我不建议尝试覆盖 dispatchEvent()
或任何其他本机方法,因为它对很多事情都不起作用。许多事件处理的事情发生在您可以使用 JavaScript.
访问的级别以下
相反,您可以尝试使用 event capture.
来实现它
如果您将 true
提供给事件的 useCapture
参数或 capture
选项,您基本上会赋予该元素优先于其他未使用捕获的元素。如果您在 html
或 body
在 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 上的任何“安全性”都只是安全区,无论实施得多么好,都可以轻易地被知识渊博的人绕过。
我想要的是,当一个元素接收到一个事件时,我希望它首先做“某事”,这个“某事”可能是评估是否调用注册的事件监听器。
我可以通过调用 .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
答案是“有时”。
我不建议尝试覆盖 dispatchEvent()
或任何其他本机方法,因为它对很多事情都不起作用。许多事件处理的事情发生在您可以使用 JavaScript.
相反,您可以尝试使用 event capture.
来实现它如果您将 true
提供给事件的 useCapture
参数或 capture
选项,您基本上会赋予该元素优先于其他未使用捕获的元素。如果您在 html
或 body
在 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 上的任何“安全性”都只是安全区,无论实施得多么好,都可以轻易地被知识渊博的人绕过。