javascript - Fjern alle hendelseslyttere av en bestemt type
Jeg vil fjerne alle hendelseslyttere av en bestemt type som ble lagt til ved bruk av addEventListener(). Alle ressursene jeg ser sier at du må gjøre dette:
elem.addEventListener('mousedown',specific_function);
elem.removeEventListener('mousedown',specific_function);
Men jeg vil kunne tømme det uten å vite hva det er for øyeblikket, slik:
elem.addEventListener('mousedown',specific_function);
elem.removeEventListener('mousedown');
Svar #1
Det er ikke mulig uten å avskjære addEventListener-kall og holde oversikt over lytterne, eller bruke et bibliotek som tillater slike funksjoner, dessverre. Det ville vært mulig hvis samlingen av lyttere var tilgjengelig, men funksjonen ble ikke implementert.
Det nærmeste du kan gjøre er å fjerne alle lyttere ved å klone elementet, noe som ikke vil klone lytterkolleksjonen.
Merk: Dette vil også fjerne lyttere på elementets barn.
var el = document.getElementById('el-id'),
elClone = el.cloneNode(true);
el.parentNode.replaceChild(elClone, el);
Svar #2
Hvis ditt eneste mål med å fjerne lytterne er å stoppe dem fra å kjøre, kan du legge til en hendelseslytter på vinduet som fanger og avbryter alle hendelser av den gitte typen:
window.addEventListener(type, function(event) {
event.stopImmediatePropagation();
}, true);
Å sende inn true for den tredje parameteren gjør at hendelsen fanges på vei ned. Å stoppe videreføring betyr at hendelsen aldri når lytterne som lytter etter den.
Husk imidlertid at dette har svært begrenset bruk, siden du ikke kan legge til nye lyttere for den gitte typen (de vil alle bli blokkert). Det finnes måter å omgå dette på en viss måte, for eksempel ved å utløse en ny type hendelse som bare dine lyttere ville vite å lytte etter. Slik kan du gjøre det:
window.addEventListener('click', function (event) {
// (note: not cross-browser)
var event2 = new CustomEvent('click2', {detail: {original: event}});
event.target.dispatchEvent(event2);
event.stopPropagation();
}, true);
element.addEventListener('click2', function(event) {
if (event.detail && event.detail.original) {
event = event.detail.original
}
// Do something with event
});
Merk imidlertid at dette kanskje ikke fungerer like godt for raske hendelser som mousemove, gitt at nyutsendelsen av hendelsen introduserer en forsinkelse.
Det ville være bedre å bare holde oversikt over lytterne som ble lagt til i utgangspunktet, som beskrevet i Martin Wantkes svar, hvis du trenger å gjøre dette.
Som en referanse: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener sier at den tredje parameteren enten er et objekt med konfigurasjon eller en boolean, der booleanen er en snarvei for "capture"-konfigurasjonen. Capture betyr at hendelsen vil bli sendt til denne tilbakekallingsfunksjonen "før" noen annen registrert handler.
Svar #3
Du må overstyre EventTarget.prototype.addEventListener for å lage en fellefunksjon for å logge alle 'legg til lytter'-kall. Noe sånt som dette:
var _listeners = [];
EventTarget.prototype.addEventListenerBase = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener)
{
_listeners.push({target: this, type: type, listener: listener});
this.addEventListenerBase(type, listener);
};
Da kan du bygge en EventTarget.prototype.removeEventListeners:
EventTarget.prototype.removeEventListeners = function(targetType)
{
for(var index = 0; index != _listeners.length; index++)
{
var item = _listeners[index];
var target = item.target;
var type = item.type;
var listener = item.listener;
if(target == this && type == targetType)
{
this.removeEventListener(type, listener);
}
}
}
I ES6 kan du bruke et Symbol for å skjule den opprinnelige funksjonen og listen over alle tilførte lyttere direkte i det instansierte objektet selv.
(function()
{
let target = EventTarget.prototype;
let functionName = 'addEventListener';
let func = target[functionName];
let symbolHidden = Symbol('hidden');
function hidden(instance)
{
if(instance[symbolHidden] === undefined)
{
let area = {};
instance[symbolHidden] = area;
return area;
}
return instance[symbolHidden];
}
function listenersFrom(instance)
{
let area = hidden(instance);
if(!area.listeners) { area.listeners = []; }
return area.listeners;
}
target[functionName] = function(type, listener)
{
let listeners = listenersFrom(this);
listeners.push({ type, listener });
func.apply(this, [type, listener]);
};
target['removeEventListeners'] = function(targetType)
{
let self = this;
let listeners = listenersFrom(this);
let removed = [];
listeners.forEach(item =>
{
let type = item.type;
let listener = item.listener;
if(type == targetType)
{
self.removeEventListener(type, listener);
}
});
};
})();
Du kan teste denne koden med dette lille utsnittet:
document.addEventListener("DOMContentLoaded", event => { console.log('event 1'); });
document.addEventListener("DOMContentLoaded", event => { console.log('event 2'); });
document.addEventListener("click", event => { console.log('click event'); });
document.dispatchEvent(new Event('DOMContentLoaded'));
document.removeEventListeners('DOMContentLoaded');
document.dispatchEvent(new Event('DOMContentLoaded'));
// click event still works, just do a click in the browser
Svar #4
Fjern alle lyttere på en global hendelse
element.onmousedown = null;
nå kan du gå tilbake til å legge til hendelseslyttere via
element.addEventListener('mousedown', handler, ...);
Denne løsningen fungerer bare på "Globale" hendelser. Egne hendelser vil ikke fungere. Her er en liste over alle globale hendelser: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers
Svar #5
En moderne måte å fjerne eventlyttere på uten å referere til den originale funksjonen er å bruke AbortController. En advarsel er at du bare kan avbryte de lytterne som du selv har lagt til.
const buttonOne = document.querySelector('#button-one');
const buttonTwo = document.querySelector('#button-two');
const abortController = new AbortController();
// Add multiple click event listeners to button one
buttonOne.addEventListener(
'click',
() => alert('First'),
{ signal: abortController.signal }
);
buttonOne.addEventListener(
'click',
() => alert('Second'),
{ signal: abortController.signal }
);
// Add listener to remove first button's listeners
buttonTwo.addEventListener(
'click',
() => abortController.abort()
);<p>The first button will fire two alert dialogs when clicked. Click the second button to remove those listeners from the first button.</p>
<button type="button" id="button-one">Click for alerts</button>
<button type="button" id="button-two">Remove listeners</button>Svar #6
Jeg vet at dette er gammelt, men jeg hadde et lignende problem uten noen riktige svar, hvor jeg ønsket å fjerne alle keydown-hendelseslyttere fra dokumentet. I stedet for å fjerne dem, overstyrer jeg addEventListener for å ignorere dem før de i det hele tatt ble lagt til, likt Toms svar ovenfor, ved å legge dette til før andre skript lastes:
<script type="text/javascript">
var current = document.addEventListener;
document.addEventListener = function (type, listener) {
if(type =="keydown")
{
//do nothing
}
else
{
var args = [];
args[0] = type;
args[1] = listener;
current.apply(this, args);
}
};
</script>
