addEventListener (and removeEventListener) function that need param

强颜欢笑 提交于 2019-12-11 07:30:09

问题


I need to add some listeners to 8 object (palms). These object are identical but the behaviour have to change basing to their position. I have the follow (ugly) code:

root.palmsStatus = ["B","B","B","B","B","B","B","B"];

if (root.palmsStatus[0] !== "N")
  root.game.palms.palm1.addEventListener("click", palmHandler = function(){ palmShakeHandler(1); });
if (root.palmsStatus[1] !== "N")
  root.game.palms.palm2.addEventListener("click", palmHandler = function(){ palmShakeHandler(2); });
if (root.palmsStatus[2] !== "N")
  root.game.palms.palm3.addEventListener("click", function(){ palmShakeHandler(3); });
if (root.palmsStatus[3] !== "N")
  root.game.palms.palm4.addEventListener("click", function(){ palmShakeHandler(4); });
if (root.palmsStatus[4] !== "N")
  root.game.palms.palm5.addEventListener("click", function(){ palmShakeHandler(5); });
if (root.palmsStatus[5] !== "N")
  root.game.palms.palm6.addEventListener("click", function(){ palmShakeHandler(6); });
if (root.palmsStatus[6] !== "N")
  root.game.palms.palm7.addEventListener("click", function(){ palmShakeHandler(7); });
if (root.palmsStatus[7] !== "N")
  root.game.palms.palm8.addEventListener("click", function(){ palmShakeHandler(8); });

I have two needs:

1) doesn't use an anonymous function on click event.

I wrote this code, but it doesn't work

root.game.palms.palm8.addEventListener("click", palmShakeHandler(8));

So this one works fine

root.game.palms.palm8.addEventListener("click", function(){ palmShakeHandler(8); });

But I didn't understand how remove the event listener. I try this solution, but it doesn't work

root.game.palms.palm8.addEventListener("click", palmHandler = function(){ palmShakeHandler(8); });
root.game.palms.palm8.removeEventListener("click", palmHandler);

2) add and remove listener in a for cycle

I wrote the follow code but the behaviour is not correct.

  for (i=1; i <= root.palmsStatus.length; i++){
    if (root.palmsStatus[i-1] !== "N"){
      root.game.palms["palm" + i].addEventListener("click", function(){ palmShakeHandler(i); });
    }
  } 

the listeners was added but the value of the parameter passed to the palmShakeHandler is always 8.

Nobody could help me to fix these issues?


回答1:


There is a actually, a perfect way to do that in JavaScript using the Function.prototype.bind method.

bind let you define extra parameters that will be passed, as arguments, of the function.

You should also keep in mind that bind creates a new function and doesn't modify the initial function.

Here is what it looks like:

function palmHandler(number) {
  // your code working with `number`
}

var palmHandler8 = palmHandler.bind(null, 8)
// the palmHandler8 is now tied to the value 8.
// the first argument (here null) define what `this` is bound to in this function

This should fix your problem, and you will be able to remove handlers easily :)

Your code will look like this:

for (i=1; i <= root.palmsStatus.length; i++){
  if (root.palmsStatus[i-1] !== "N"){
    root.game.palms["palm" + i].addEventListener("click", palmShakeHandler.bind(null, i));
  }
} 

To be able to remove the handler afterward, you need to keep a reference to the function you create with bind. This would be the way to do this.

var boundHandler = handler.bind(null, i);
element.addEventListener(boundHandler);
element.removeEventListener(bounderHander);

If you want to know more about the awesome bind method in JavaScript, the MDN is your friend :) https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

BTW, the problem with you function always returning 8 is a very common question in JavaScript. This thread will explain everything (spoiler, it's a matter of scoping :) ) https://stackoverflow.com/a/750506/2745879




回答2:


So in case your array of »palms« is very huge, it is basically a bad Idea to add a single event listener to each of them, because that causes performance flaws. So I would suggest a different approach:

var handlers = [function (e) {}, …, function (e) {}];

root.game.palms.forEach(functiion (palm, idx) {
  palm.setAttribute('data-idx', idx);
});

<palmsparent>.addEventListener('click', function (e) {
  var c = e.target, idx = -1;

  while (c) {
    if (c.hasAttribute && c.hasAttribute('data-idx')) {
      idx = parseInt(c.getAttribute('data-idx'));
      break;
    }
    c = c.parentNode;
  }

  //here you also check for the »palm status«
  if (idx >= 0) {
    handlers[idx](c);
  }
})

One event listener for all, much easier to remove and better for performance.




回答3:


In your last solution you are pasing the same var to every function and that is what make al the functions work with 8 because is the last value of the variable.

To work arround that you can use "let" ( please at least use var, otherside that "i" is global and can be changed every where in the code) but since I dont know wich browser you target I propose other solution.

for (var i=1; i <= root.palmsStatus.length; i++){
    if (root.palmsStatus[i-1] !== "N"){
      root.game.palms["palm" + i].addEventListener("click", (function(index)
      (return function(){ 
        palmShakeHandler(index); 
      }))(i);
    }
  } 

Since its look like You are targeting modern browsers I will use let.https://kangax.github.io/compat-table/es6/

for (var i=1; i <= root.palmsStatus.length; i++){
    let index = i;
    let intermediateFunction = function(){palmShakeHandler(index);};
    if (root.palmsStatus[i-1] !== "N"){
      root.game.palms["palm" + i].addEventListener("click",intermediateFunction);
      root.game.palms["palm" + i].removeHandShake = function(){this.removeEventListener("click",intermediateFunction)};
    }
  } 

So now you just need to call "removeHandShake" and will remove the listener,

I have code this right here so it ease some minor errors to pop



来源:https://stackoverflow.com/questions/44257208/addeventlistener-and-removeeventlistener-function-that-need-param

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!