Добавить прослушиватель событий для нескольких сгенерированных элементов - PullRequest
1 голос
/ 14 апреля 2020

Я пытаюсь сделать Ti c -Ta c -Toe для моей школы в чистом JS и основанном на CSS и HTML GUI. Я знаю, что это, вероятно, не лучший подход, но я подумал, что это может сработать. К сожалению, это не работает вообще.

Я пытаюсь сгенерировать всю доску на JS в Board.generate(), потому что я хочу сделать мою доску изменяемой, а затем добавить прослушиватели событий для каждого сгенерированного клетка, но это не работает. 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>

Я знаю, что мой код сейчас беспорядок, но я был просто расстроен, и это всего лишь набросок, я над ним поработаю. Кроме того, извините за мой Engli sh, если я сделал несколько ошибок.

1 Ответ

0 голосов
/ 14 апреля 2020

Каждый раз, когда вы устанавливаете свойство 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>
...