将事件侦听器添加到多个生成的元素

时间:2020-04-13 22:25:38

标签: javascript html onclick

我正试图用纯JS并基于CSS和HTML GUI为我的学校制作井字游戏。我知道这可能不是最好的方法,但我认为这可能有效。不幸的是,它根本不起作用。

我正在尝试在Board.generate()中用JS生成整个电路板,因为我想使我的电路板可调整大小,然后将事件侦听器添加到每个生成的单元格中,但这是行不通的。 Onclick仅在最后一个元素上调用,而不在先前的元素上调用。我想我可以通过创建一个函数来绕过此问题,但是我想了解为什么我的代码无法正常工作。

这是我的代码:

class Board {
  constructor(size) {
    this.size = size;
 
    this.cells = [];
    for (let x = 0; x < size; x++) {
      this.cells[x] = [];
      for (let y = 0; y < size; y++) {
        this.cells[x][y] = new Cell(x, y, null);
      }
    }
  }
 
  generate() {
    document.getElementById('game').innerHTML = '<div id="board"></div>';
 
    let boardEl = document.getElementById('board');
 
    for (let y = 0; y < this.size; y++) {
      boardEl.innerHTML += '<div id="r' + y + '" class="board-row"></div>';
      let rowEl = document.getElementById('r' + y);
 
      for (let x = 0; x < this.size; x++)
        this.cells[x][y].addElement(rowEl);
    }
  }
}
 
class Cell {
  constructor(x, y, mark) {
    this.x = x;
    this.y = y;
    this.mark = mark;
    this.id = 'c' + x + y;
    this.element = null;
  }
 
  addElement(rowEl) {
    rowEl.innerHTML += '<div id="' + this.id + '" class="board-cell"> CELL </div>';
    this.element = document.getElementById(this.id);
    this.element.addEventListener('click', () => this.clicked(), false);
  }
 
  clicked() {
    console.log(this.x, this.y, ' CLICKED!');
  }
}
 
window.onload = function () {
  var game = new Board(3);
  game.generate();
};
<style>
  .board-cell {
    width: 10%;
    height: 10%;
    background: white;
    color:black;
  }
</style>
<div id="container" class="fullscreen">

  <div id="game" class="fullscreen">

    <!-- Generated board -->

  </div>

</div>

我知道我的代码现在一团糟,但是我很沮丧,这只是一个草图,我将继续研究。 另外,如果我犯了一些错误,请为我的英语感到抱歉。

1 个答案:

答案 0 :(得分:0)

每次设置innerHTML属性时,都会覆盖以前在此处设置的所有HTML。这包括串联分配,因为

element.innerHTML += '<b>Hello</b>';

与写作相同

element.innerHTML = element.innerHTML + '<b>Hello</b>';

这意味着所有未通过HTML属性附加的处理程序都将被“分离”,因为它们附加的元素不再存在,并且已替换了一组新元素。为了保留所有以前的事件处理程序,必须添加元素而不覆盖任何以前的HTML。最好的方法是使用DOM创建功能,例如createElement和appendChild:

let divEl  = document.createElement("div");
divEl.innerHTML = "CELL";   
divEl.className = 'board-cell'
divEl.id = this.id;
rowEl.appendChild(divEl);

行div元素也是如此:

let divRowEl  = document.createElement("div");
divRowEl.className = 'board-row'
divRowEl.id = 'r' + y;
boardEl.appendChild(divRowEl);

class Board {
  constructor(size) {
    this.size = size;
 
    this.cells = [];
    for (let x = 0; x < size; x++) {
      this.cells[x] = [];
      for (let y = 0; y < size; y++) {
        this.cells[x][y] = new Cell(x, y, null);
      }
    }
  }
 
  generate() {
    
    document.getElementById('game').innerHTML = '<div id="board"></div>';
 
    let boardEl = document.getElementById('board');
 
    for (let y = 0; y < this.size; y++) {
      let divRowEl  = document.createElement("div");
      divRowEl.className = 'board-row'
      divRowEl.id = 'r' + y;
      boardEl.appendChild(divRowEl);
      let rowEl = document.getElementById('r' + y);
      
      for (let x = 0; x < this.size; x++)
        this.cells[x][y].addElement(rowEl);
    }
  }
}
 
class Cell {
  constructor(x, y, mark) {
    this.x = x;
    this.y = y;
    this.mark = mark;
    this.id = 'c' + x + y;
    this.element = null;
  }
 
  addElement(rowEl) {
    let divEl  = document.createElement("div");
    divEl.innerHTML = "CELL" + this.id;   
    divEl.className = 'board-cell'
    divEl.id = this.id;
    divEl.addEventListener('click', () => this.clicked(), false);
    rowEl.appendChild(divEl);
  }
 
  clicked() {
    console.log(this.x, this.y, ' CLICKED!');
  }
}
 
window.onload = function () {
  var game = new Board(3);
  game.generate();
};
<style>
  .board-cell {
    width: 10%;
    height: 10%;
    background: white;
    color:black;
  }
</style>
<div id="container" class="fullscreen">

  <div id="game" class="fullscreen">

    <!-- Generated board -->

  </div>

</div>