Как правильно удалить eventListener?

1

Я получаю удовольствие от ванильного палочки JS Tic tac Каждая клетка - это кнопка. Чтобы обрабатывать клики, я добавляю eventListener в wrapping div:

board.addEventListener("click", handleClick, true);

И позже в функции printWinner() я попытаюсь удалить его без эффекта...

const printWinner = (winner) => {
    // ...
    board.removeEventListener("click", handleClick);
}

Как удалить этот eventListener?

Полный код:

// Some settings
const symbols = ['X', '0'];
const board   = document.querySelector('#board');

// Append a result popup
const results = document.createElement("div");
results.classList.add("message");
document.body.insertBefore(results, board);

// Winning combinations
const combinations = [
  [1,2,3],
  [4,5,6],
  [7,8,9],
  [1,4,7],
  [2,5,8],
  [3,6,9],
  [1,5,9],
  [7,5,3]
]

// Base variables
let i = 1;
let move= 0;

// Check if there a winner
const checkWin = () => {
  let winner = false;

  combinations.forEach(combination => {
    let c0 = board.querySelector('#c${combination[0]}').innerHTML || undefined;
    let c1 = board.querySelector('#c${combination[1]}').innerHTML || undefined;
    let c2 = board.querySelector('#c${combination[2]}').innerHTML || undefined;

    if (c0 === c1 && c0 === c2 && c0 !== undefined) {
      winner = symbols.indexOf(c0) + 1;
      printWinner(winner);
      return;
    }
  });
}

// Cells click handling
const handleClick = (event) => {
  if(!event.target.innerHTML && event.target.nodeName == 'BUTTON') {
    let currSymbol = move % 2 ? symbols[1] : symbols[0];
    event.target.innerHTML = currSymbol;
    event.target.setAttribute("disabled", true);
    event.preventDefault();
    checkWin();
    move++;
  }
}

// Bind the click handler
board.addEventListener("click", handleClick, true);

// Print the winner
const printWinner = (winner) => {
  let winnerMessage = document.createTextNode('Player ${winner} wins!');
  results.appendChild(winnerMessage);
  results.classList.add("is-visible");
  setTimeout(() => {
    results.classList.remove("is-visible");
  }, 4000)
  board.removeEventListener("click", handleClick);
}

// Fill the board
(function fillDom() {
  let dom = '';
  for (let row = 1; row <= 3; row++) {
    dom += '<div class="board__row">';

    for (let cell = 1; cell <= 3; cell++) {
      dom += '<button id="c${i}" class="board__cell"></button>';

      if (cell == 3) {
        dom += '</div>';
      }
      i++;
    }
  }
  board.innerHTML = dom;
})();
:root {
  --bgColor: #fff;
  --mainColor: #04e;
  --mainColor-hover: #dde7ff;
  --mainColor-active: #eef3ff;
  --messageColor: #04e;
}
html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
  padding: 0;
  margin: 0;
}
body {
  background-color: var(--bgColor);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  font-size: 18px;
  line-height: 1.48;
}
.board {
  width: 300px;
  height: 300px;
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}
.board__row {
  width: 100%;
  border-bottom: 2px solid var(--mainColor);
  display: flex
}
.board__row:last-of-type {
  border-bottom: 0;
}
.board__cell {
  flex: 1 1 auto;
  width: 100px;
  height: 100px;
  text-align: center;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border: 0;
  border-radius: 0;
  border-right: 2px solid var(--mainColor);
  font-size: 24px;
  font-weight: 600;
  outline: 0;
  cursor: pointer;
  color: var(--mainColor);
  background-color: var(--bgColor);
  transition: background-color 160ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
}
.board__cell:hover {
  background-color: var(--mainColor-hover);
}
.board__cell[disabled] {
  background-color: var(--mainColor-active);
}
.board__row .board__cell:last-child {
  border-right: 0;
}
.message {
  position: fixed;
  z-index: 1;
  top: 0;
  left: 50%;
  opacity: 0;
  transform: translate(-50%, -100px);
  transition: all 400ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
  color: #fff;
  background-color: var(--messageColor);
  border-radius: 4px;
  padding: 12px 24px;
  box-shadow: 0 2px 8px rgba(0,0,0,.16)
}
.message.is-visible {
  opacity: 1;
  transform: translate( -50%, 24px);
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
<div id="board" class="board"></div>

Или посмотрите на копейфель.

  • 1
    Здравствуй! Добро пожаловать в стек переполнения. Спасибо за предоставление всего, что нам нужно, чтобы помочь. Кроме того, я преобразовал ваш кодекс в готовый сниппит; облегчает просмотр всего этого в одном месте, и мы можем скопировать код в ответ.
  • 1
    .removeEventListener(type, listener[, useCapture]) : " .removeEventListener(type, listener[, useCapture]) событий, который необходимо удалить, идентифицируется с использованием комбинации типа события, самой функции прослушивателя событий и различных необязательных опций, которые могут влиять на процесс сопоставления; см. Соответствующие прослушиватели событий для удаления "
Теги:
event-handling
events

1 ответ

2
Лучший ответ

Проблема в том, как вы используете флаг "захват".

Когда вы настраиваете прослушиватель событий, вы регистрируете его как приемник захвата:

board.addEventListener("click", handleClick, true);
//                                       -----^

Но когда вы пытаетесь удалить его, вы не указываете прослушиватель захвата:

// Notice the lack of a third argument
board.removeEventListener("click", handleClick);

Чтобы указать страницу MDN:

Удаление приемника захвата не влияет на неконвертирующую версию одного и того же прослушивателя и наоборот.

Итак, вам нужно указать, что вы хотите удалить приемник захвата:

board.removeEventListener("click", handleClick, true);

Ваш код с этим изменением:

// Some settings
const symbols = ['X', '0'];
const board   = document.querySelector('#board');

// Append a result popup
const results = document.createElement("div");
results.classList.add("message");
document.body.insertBefore(results, board);

// Winning combinations
const combinations = [
  [1,2,3],
  [4,5,6],
  [7,8,9],
  [1,4,7],
  [2,5,8],
  [3,6,9],
  [1,5,9],
  [7,5,3]
]

// Base variables
let i = 1;
let move= 0;

// Check if there a winner
const checkWin = () => {
  let winner = false;

  combinations.forEach(combination => {
    let c0 = board.querySelector('#c${combination[0]}').innerHTML || undefined;
    let c1 = board.querySelector('#c${combination[1]}').innerHTML || undefined;
    let c2 = board.querySelector('#c${combination[2]}').innerHTML || undefined;

    if (c0 === c1 && c0 === c2 && c0 !== undefined) {
      winner = symbols.indexOf(c0) + 1;
      printWinner(winner);
      return;
    }
  });
}

// Cells click handling
const handleClick = (event) => {
  if(!event.target.innerHTML && event.target.nodeName == 'BUTTON') {
    let currSymbol = move % 2 ? symbols[1] : symbols[0];
    event.target.innerHTML = currSymbol;
    event.target.setAttribute("disabled", true);
    event.preventDefault();
    checkWin();
    move++;
  }
}

// Bind the click handler
board.addEventListener("click", handleClick, true);

// Print the winner
const printWinner = (winner) => {
  let winnerMessage = document.createTextNode('Player ${winner} wins!');
  results.appendChild(winnerMessage);
  results.classList.add("is-visible");
  setTimeout(() => {
    results.classList.remove("is-visible");
  }, 4000)
  board.removeEventListener("click", handleClick, true);
}

// Fill the board
(function fillDom() {
  let dom = '';
  for (let row = 1; row <= 3; row++) {
    dom += '<div class="board__row">';

    for (let cell = 1; cell <= 3; cell++) {
      dom += '<button id="c${i}" class="board__cell"></button>';

      if (cell == 3) {
        dom += '</div>';
      }
      i++;
    }
  }
  board.innerHTML = dom;
})();
:root {
  --bgColor: #fff;
  --mainColor: #04e;
  --mainColor-hover: #dde7ff;
  --mainColor-active: #eef3ff;
  --messageColor: #04e;
}
html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
  padding: 0;
  margin: 0;
}
body {
  background-color: var(--bgColor);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  font-size: 18px;
  line-height: 1.48;
}
.board {
  width: 300px;
  height: 300px;
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}
.board__row {
  width: 100%;
  border-bottom: 2px solid var(--mainColor);
  display: flex
}
.board__row:last-of-type {
  border-bottom: 0;
}
.board__cell {
  flex: 1 1 auto;
  width: 100px;
  height: 100px;
  text-align: center;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border: 0;
  border-radius: 0;
  border-right: 2px solid var(--mainColor);
  font-size: 24px;
  font-weight: 600;
  outline: 0;
  cursor: pointer;
  color: var(--mainColor);
  background-color: var(--bgColor);
  transition: background-color 160ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
}
.board__cell:hover {
  background-color: var(--mainColor-hover);
}
.board__cell[disabled] {
  background-color: var(--mainColor-active);
}
.board__row .board__cell:last-child {
  border-right: 0;
}
.message {
  position: fixed;
  z-index: 1;
  top: 0;
  left: 50%;
  opacity: 0;
  transform: translate(-50%, -100px);
  transition: all 400ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
  color: #fff;
  background-color: var(--messageColor);
  border-radius: 4px;
  padding: 12px 24px;
  box-shadow: 0 2px 8px rgba(0,0,0,.16)
}
.message.is-visible {
  opacity: 1;
  transform: translate( -50%, 24px);
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
<div id="board" class="board"></div>
  • 0
    О, здорово, это решило проблему. Спасибо тебе Майк!
  • 0
    @ BenjaminRéthoré Не беспокойся. Рад, что смог помочь!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню