Javascript RemoveEventListener 不工作

我有以下代码来添加 Event Listener

 area.addEventListener('click',function(event) {
app.addSpot(event.clientX,event.clientY);
app.addFlag = 1;
},true);

它正在按预期正常工作. . 稍后在另一个函数中,我尝试使用以下代码删除事件侦听器

 area.removeEventListener('click',function(event) {
app.addSpot(event.clientX,event.clientY);
app.addFlag = 1;
},true);

但是偶数侦听器并没有被删除. . 为什么会发生这种情况? 我删除的 EventListener ()有什么问题吗? 注意: 这里的区域类似于 document.getElementById (‘ myId’)

140282 次浏览

To remove it, store the function in a variable or simply use a named function and pass that function to the removeEventListener call:

function areaClicked(event) {
app.addSpot(event.clientX, event.clientY);
app.addFlag = 1;
}


area.addEventListener('click', areaClicked, true);
// ...
area.removeEventListener('click', areaClicked, true);

This is because that two anonymous functions are completely different functions. Your removeEventListener's argument is not a reference to the function object that was previously attached.

function foo(event) {
app.addSpot(event.clientX,event.clientY);
app.addFlag = 1;
}
area.addEventListener('click',foo,true);
area.removeEventListener('click',foo,true);

define your Event Handler first,

and then

area.addEventListener('click',handler);
area.removeEventListener('click',handler);

You are creating two different functions in both calls. So the second function does not relate in any way to the first one and the engine is able to remove the function. Use a common identifier for the function instead.

var handler = function(event) {
app.addSpot(event.clientX,event.clientY);
app.addFlag = 1;
};
area.addEventListener('click', handler,true);

later you can then remove the handler by calling

area.removeEventListener('click', handler,true);

If you want to pass local variables to the function called by the event listener, you can define the function inside the function (to get the local variables) and pass the name of the function in the function itself. For example, let's start inside the function that adds the event listener with app as a local variable. You would write a function inside this function such as,

function yourFunction () {
var app;


function waitListen () {
waitExecute(app, waitListen);
}


area.addEventListener('click', waitListen, true);
}

Then you have what you need to remove it when waitExecute is called.

function waitExecute (app, waitListen) {
... // other code
area.removeEventListener('click', waitListen, true);
}

I find that for the windows object, the last param "true" is required. The remove doesn't work if there is no capture flag.

This is what I ended up doing but it's in a route class but should not make much difference, I wanted for the event listener not to accumulate each time afterModel() is called but also needed arguments and scope so that the model is changed each time.

export default class iFrameRoute extends Route {


afterModel(model) {


this.initFrame = function(event) {
    

alert("I am being called");


window.removeEventListener("message",  this.route.test);


}.bind({route: this, data: model});


window.addEventListener("message",  this.initFrame );
}
}

In a React function component, make sure to define the callback with the useCallback(() => {}) hook. If you fail to do this, the callback will be a different one on every re-render and the removeEventListener method will not work.

const scrollCallback = useCallback(() => { // do sth. });
window.addEventListener("scroll", scrollCallback, true);
window.removeEventListener("scroll", scrollCallback, true);

It looks like no one's covered the part of the JavaScript specification that now gives you a mechanism to remove your event listener without using removeEventListener. If we look at https://dom.spec.whatwg.org/#concept-event-listener we see that there are a number of properties that can be passed as options when setting up an event listener:

{
type (a string)
callback (an EventListener object, null by default)
capture (a boolean, false by default)
passive (a boolean, false by default)
once (a boolean, false by default)
signal (an AbortSignal object, null by default)
removed (a boolean for bookkeeping purposes, false by default)
}

Now, there's a lot of useful properties in that list, but for the purposes of removing an event listener it's the signal property that we want to make use of (which was added to the DOM level 3 in late 2020), because it lets us tell the JS engine to remove an event listener by using an AbortController instead of having to bother with keeping a reference to the exact handler function and listener options "because otherwise removeEventListener won't even work properly":

const areaListener = new AbortController();


area.addEventListener(
`click`,
({clientX: x, clientY: y}) => {
app.addSpot(x, y);
app.addFlag = 1;
},
areaListener // or { signal: areaListener.signal } of course
);

And now, when it's time to remove that event listener, we simply run:

areaListener.abort()

And done: the JS engine will abort and clean up our event listener. No keeping a reference to the handling function, no making sure we call removeEventListener with the exact same properties as we called addEventListener: we just cancel the listener.

And of course, also note that if we want to do this "because we only want the handler to fire once", then we don't even need to do this, we can just create an event listener with { once: true } and JS will take care of the rest. No removal code required.

area.addEventListener(
`click`,
() => app.bootstrapSomething(),
{ once: true }
);

while adding function store in array and removing pass by map work for me

const [functionObjects, setfunctionObjects] = useState([]);


const addListener = (beforeUnloadListener) =>{
setfunctionObjects([...nano, beforeUnloadListener]);
addEventListener("beforeunload", beforeUnloadListener, {capture: true});
};


const removeListener = (beforeUnloadListener) => {
functionObjects.map((item) => {
removeEventListener("beforeunload", item, {capture: true});});
};

I went through this same problem recently. A reasonble solution that I found was remove attribute "onclick" on element from HTMLElement class.

Let's imagine that you already got your component from DOM - using document.getElementById or document.querySelector - you can try that code:

js

const element = document.getElementById("myelement");
element.attributes.removeNamedItem('onclick');

html example

<div onClick="memoryGame.flipCard(this)">
.... // children elements
</div>

I know which this solution it ins't the best, but it works!

I hope I was able to help you.

Cheers!

PS: please, give me a "useful answer"... thanks :D

In case of React we can use useRef() to store our listener function in current property. So that in case of re-render and in case of remove listener it will maintain the same reference to the function.

const handleWindowClick = useRef(() => {
console.log("window clicked");
});






// for attaching event listener
window.addEventListener("click", handleWindowClick.current);
 

// for detaching event listener
window.removeEventListener("click", handleWindowClick.current);