最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Js: remove or disable previous added event listeners of a certain event - Stack Overflow

programmeradmin4浏览0评论

codepen

Take following example (same as codepen)

const div = document.querySelector('div');

function a(){
  console.log('a');
}

function b(){
  console.log('b');
}

div.addEventListener('click', e=>{
  a();
});

div.addEventListener('click', e=>{
  // I don't want all previous added event handlers to work, is there a way to remove it?
  b();
});
div{
  width: 200px;
  height: 200px;
  background: red;
}
<div></div>

codepen

Take following example (same as codepen)

const div = document.querySelector('div');

function a(){
  console.log('a');
}

function b(){
  console.log('b');
}

div.addEventListener('click', e=>{
  a();
});

div.addEventListener('click', e=>{
  // I don't want all previous added event handlers to work, is there a way to remove it?
  b();
});
div{
  width: 200px;
  height: 200px;
  background: red;
}
<div></div>

the expected output is b;

In my original code, I have more than one event handlers, such as click, mousemove, etc. is there a way I can remove all event listeners of a particular event that I previously added?

For example, at the start, click to my button triggers function A; in the middle, I consider needing a functional change, so instead of triggering function A, I want function B, and only function B.

I have read:

  • JavaScript: remove event listener

but it didn't help much. thanks for your help.


update

To be more specific, is there a way to prevent previously added event listeners of click inside the new added function, for instance:


my_button.addEventListener('click', ()=>{
    console.log('a');
});

my_button.addEventListener('click', ()=>{
    // remove all previously added click handlers 
    console.log('b');
});


solution

Thanks to @Kayac, worked this out:

// add a new method to element, oneEventListener, 
// for a speficified event type, only save and execute last add handler

function elemental(el){
    el.oneEventListener = (event, func) => {
        if(el.lastEventListener == null){
          el.lastEventListener = {};
        }
        if(el.lastEventListener[event] != null){
          el.removeEventListener(event, el.lastEventListener[event]);
        }
        el.addEventListener(event, func);
        el.lastEventListener[event] = func;
    }
    return el;
}

// eventhandler singleton, support querySelector, getElementById, etc, even support querySelectorAll and getElementsByClassName
function proxy(el) {
  if(!(el instanceof NodeList)){
    return elemental(el);
  }else{
    el.forEach(ele=>{
      ele = elemental(ele);
    });
    return el;
  }
}

const div = proxy(document.querySelector('div'));
// const div = document.querySelector('div');

div.oneEventListener('click', e=>{
    console.log('a');
})

div.oneEventListener('click', e=>{
    console.log('b');
})

div.oneEventListener('click', ()=>{
    console.log('c');
})

div.oneEventListener('mouseover', ()=>{
    console.log('aa');
})

div.oneEventListener('mouseover', ()=>{
    console.log('bb');
})

div.oneEventListener('mouseover', ()=>{
    console.log('cc');
})
div{
  width: 200px;
  height: 200px;
  background: red;
}
<div></div>

Update

For visitors, if you are looking for html selector to allow you to perform singleton on event listener, following code is tuned for performance.

/* html element selector */

// element: one event maps to one handler
function elemental(el){
  el.oneEventListener = (event, func) => {
    if(el.lastEventListener == null){
      el.lastEventListener = {};
    }
    if(el.lastEventListener[event] != null){
      el.removeEventListener(event, el.lastEventListener[event]);
    }
    el.addEventListener(event, func);
    el.lastEventListener[event] = func;
  }
  return el;
}

// querySelector -> element
function proxy(el){
  return elemental(el);
}

// querySelectorAll -> NodeList
function proxyAll(el){
  el.forEach(ele=>{
    ele = elemental(ele);
  });
  return el;
}

/*
once proxy is implemented, by oneEventListener, 
only one event listener of particular type will exist on that element,
if you call addEventListener, proxy doesn't interfer it.
which the eventlistener added will work normally.
*/

// proxy query selector
const pqs = function(str){
  return proxy(document.querySelector(str));
}

// proxy query selector all
const pqsa = function(str){
  return proxyAll(document.querySelectorAll(str));
}
Share Improve this question edited Aug 28, 2021 at 21:47 Daniel Widdis 9,16013 gold badges48 silver badges68 bronze badges asked Oct 1, 2020 at 12:27 WeiloryWeilory 3,11723 silver badges39 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 1

Try this

function a() {
  console.log("a");
}

function b() {
  console.log("b");
}

function proxy(el) {
  const map = {};

  return {
    addEventListener: (event, func) => {
      !map[event] && el.addEventListener(event, () => map[event]());

      map[event] = func;
    }
  };
}

const div = proxy(document.querySelector("div"));

div.addEventListener("click", a);
div.addEventListener("click", b);

You need to remove the previous event listener by reference: https://developer.mozilla/en-US/docs/Web/API/EventTarget/removeEventListener

try this:

const div = document.querySelector('div');

function a(){
  console.log('a');
}

function b(){
  console.log('b');
}

div.addEventListener('click', a);

// condition for changing event listener
if (true) {
    div.removeEventListener('click', a);
}

div.addEventListener('click', b);

This should only run b

Did you try this?

removeEventListener

It removes a "click" event that has been attached with the addEventListener() method:

Example

// Attach an event handler to <div>
document.getElementById("myDIV").addEventListener("click", myFunction);

// Remove the event handler from <div>
document.getElementById("myDIV").removeEventListener("click", myFunction);

I'm afraid you have to keep track of the events you're attaching to an element using addEventListener yourself. There's no built-in method to query those. To successfully remove an event using removeEventListener, it must have the same signature as the call to addEventListener.

This is done by using a named function instead of an anonymous function.

For example:

var myButton = document.getElementById("myButton");
var myButton2 = document.getElementById("myButton2");

function a() {
  console.log("function a");
}

function b() {
  console.log("function b");
}

function changeFunction() {
  myButton.removeEventListener('click', a);
  myButton.addEventListener('click', b);
}
myButton.addEventListener('click', a);
myButton2.addEventListener('click', changeFunction);
<button id="myButton">
click me
</button>
<button id="myButton2">
attach new listener
</button>

There's no straightforward way to do that.

However, if you control all the listener additions and removals, you can collect the listeners and remove all, like this:

const elements = new WeakMap

function customAddEventListener(elem, event, fn){
  elem.addEventListener(event, fn)

  if(!elements.has(elem)) elements.set(elem, Object.create(null))
  const events = elements.get(elem)
  if(!(event in events)) events[event] = new Set
  const fns = events[event]

  fns.add(fn)
}
function customRemoveEventListener(elem, event, fn){
  elem.removeEventListener(event, fn)

  if(!elements.has(elem)) return
  const events = elements.get(elem)
  if(!event in events) return
  const fns = events[event]

  fns.delete(fn)

  if(!fns.size) delete events[event]
  if(!Reflect.ownKeys(events).length) elements.delete(elem)
}

function removeAllEventListeners(elem, event){

  if(!elements.has(elem)) return
  const events = elements.get(elem)
  if(!event in events) return
  const fns = events[event]

  for(const fn of fns)
    elem.removeEventListener(event, fn)

  delete events[event]
  if(!Reflect.ownKeys(events).length) elements.delete(elem)
}


const div = document.querySelector('#div');

function a(){
  console.log('a');
}

function b(){
  console.log('b');
}

customAddEventListener(div, 'click', e=>{
  a();
});

customAddEventListener(div, 'click', function fn(e){
  b();
  removeAllEventListeners(div, 'click')
  //add this one back
  customAddEventListener(div, 'click', fn)
});
#div{
  width: 200px;
  height: 200px;
  background: red;
}
<div id="div"></div>

It really depends if you want other things to fire, that may have been added in a different part of the code. But if you know, that you will only want a single function to run at the click event, you may stop using addEventListener and downgrade to using old and absolete .onclick.

So

my_button.onclick = ()=>{
    console.log('a');
};

// now if the button is clicked you'll see 'a'

my_button.onclick = ()=>{
    // remove all previously added click handlers 
    console.log('b');
};

// now you will no longer see 'a', but rather see 'b'
发布评论

评论列表(0)

  1. 暂无评论