简体   繁体   中英

Anonymous Function not working with keydown events

Wondering what I'm doing wrong here - the function is supposed to look at all the cells in a table, add their default background color, font color and border color and then add an Event Listener to each that executes the anonymouse function to change a cells formatting depending on what key is held down onmousedown. It does the initial styling of all the cells correctly but that's it.

function setupPuzzle() {
  allCells = document.querySelectorAll("table#hitoriGrid td");
  for (var i = 0; i < allCells.length; i++) {
    allCells[i].style.backgroundColor = "rgb(255,255,255)";
    allCells[i].style.color = "rgb(0,0,0)";
    allCells[i].style.borderRadius = "0px";
    allCells[i].addEventListener("onmousedown", function(e) {
      e.preventDefault();
      if (e.shiftKey) {
        allCells[i].style.backgroundColor = "rgb(255,255,255)";
        allCells[i].style.color = "rgb(0,0,0)";
        allCells[i].style.borderRadius = "0px";
      } else if (e.altKey) {
        allCells[i].style.backgroundColor = "rgb(0,0,0)";
        allCells[i].style.color = "rgb(255,255,255)";
        allCells[i].style.borderRadius = "0px";
      } else {
        allCells[i].style.backgroundColor = "rgb(101,101,101)";
        allCells[i].style.color = "rgb(255,255,255)";
        allCells[i].style.borderRadius = "50%";
      }
    });
  }
}

Short answer is that you are listening for an onmousedown event so e.altKey and e.shiftKey is always false because the event passed to your callback function is an onmousedown event. I am not sure if you can actually read if a key is already pressed but one of solutions that come to my mind is to listen on events for keydown and store something like:

var keyPressed = [];
window.onkeyup = function(e) {keys[e.keyCode]=false;}
window.onkeydown = function(e) {keys[e.keyCode]=true;}

Then on mouse down event you can check in an array if key is pressed.

Edit: use mousedown instead of onmousedown for the event name as pointed out by the other answers. This edit has been made in the below code:


The issue is that i does not point to the value that you expect it to. The scope of i is not confined to the block that it is contained in, so all of your onmousedown callbacks are going to reference an i that is equal to allCells.length + 1

i is incremented by 1 on each iteration of the for-loop, and this i value is shared by all of your onmousedown handlers, so by the time your for-loop finishes running, your handlers will all refer to i , which will be allCells.length + 1 as that is the last value i takes before the for-loop exits.

If you are using ES6, you can use let instead of var in your for-loop to fix the issue:

function setupPuzzle() {

  allCells = document.querySelectorAll("table#hitoriGrid td");

  for (let i = 0; i < allCells.length; i++) { // uset let instead of var

    allCells[i].style.backgroundColor = "rgb(255,255,255)";
    allCells[i].style.color = "rgb(0,0,0)";
    allCells[i].style.borderRadius = "0px";
    allCells[i].addEventListener("mousedown", function(e) {
      e.preventDefault();
      if (e.shiftKey) {
        allCells[i].style.backgroundColor = "rgb(255,255,255)";
        allCells[i].style.color = "rgb(0,0,0)";
        allCells[i].style.borderRadius = "0px";
      } else if (e.altKey) {
        allCells[i].style.backgroundColor = "rgb(0,0,0)";
        allCells[i].style.color = "rgb(255,255,255)";
        allCells[i].style.borderRadius = "0px";
      } else {
        allCells[i].style.backgroundColor = "rgb(101,101,101)";
        allCells[i].style.color = "rgb(255,255,255)";
        allCells[i].style.borderRadius = "50%";
      }
    });
  }
}

If you are not using ES6, you can use a closure to make sure that i is scoped at the block-level (and therefore all of your event handlers will have their own reference of i ):

function setupPuzzle() {

  allCells = document.querySelectorAll("table#hitoriGrid td");

  for (var i = 0; i < allCells.length; i++) { 

    (function(i) { // closure

        allCells[i].style.backgroundColor = "rgb(255,255,255)";
        allCells[i].style.color = "rgb(0,0,0)";
        allCells[i].style.borderRadius = "0px";
        allCells[i].addEventListener("mousedown", function(e) {
          e.preventDefault();
          if (e.shiftKey) {
            allCells[i].style.backgroundColor = "rgb(255,255,255)";
            allCells[i].style.color = "rgb(0,0,0)";
            allCells[i].style.borderRadius = "0px";
          } else if (e.altKey) {
            allCells[i].style.backgroundColor = "rgb(0,0,0)";
            allCells[i].style.color = "rgb(255,255,255)";
            allCells[i].style.borderRadius = "0px";
          } else {
            allCells[i].style.backgroundColor = "rgb(101,101,101)";
            allCells[i].style.color = "rgb(255,255,255)";
            allCells[i].style.borderRadius = "50%";
          }
        });

    })(i); // captures surrounding value of i

  }
}
  1. Use mousedown instead of onmousedown
  2. because your anonymous function invoked after the loop (When the user clicked it) then i value will be the last value of i . so you need to use this instead of allCells[i] .

 function setupPuzzle() { allCells = document.querySelectorAll("table#hitoriGrid td"); for (var i = 0; i < allCells.length; i++) { allCells[i].style.backgroundColor = "rgb(255,255,255)"; allCells[i].style.color = "rgb(0,0,0)"; allCells[i].style.borderRadius = "0px"; allCells[i].addEventListener("mousedown", function(e) { e.preventDefault(); if (e.shiftKey) { this.style.backgroundColor = "rgb(255,255,255)"; this.style.color = "rgb(0,0,0)"; this.style.borderRadius = "0px"; } else if (e.altKey) { this.style.backgroundColor = "rgb(0,0,0)"; this.style.color = "rgb(255,255,255)"; this.style.borderRadius = "0px"; } else { this.style.backgroundColor = "rgb(101,101,101)"; this.style.color = "rgb(255,255,255)"; this.style.borderRadius = "50%"; } }); } } setupPuzzle(); 
 <table id="hitoriGrid" border="2"> <tr> <td>Test</td> <td>Test</td> </tr> </table> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM