如何正确删除eventListener?

时间:2017-10-30 15:04:44

标签: javascript events event-handling

我正在玩一款香草JS Tic Tac toe 每个单元格都是一个按钮。要处理点击,我将一个eventListener添加到包装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's 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>

或者看on codepen

1 个答案:

答案 0 :(得分:2)

问题在于你如何使用&#34;捕获&#34;标志。

设置事件监听器时,您将其注册为捕获侦听器:

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

但是当您尝试删除它时,您没有指定捕获侦听器:

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

引用MDN page

  

删除捕获侦听器不会影响同一侦听器的非捕获版本,反之亦然。

所以您需要做的是指定要删除捕获侦听器:

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

您的代码已进行此更改:

&#13;
&#13;
// 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's 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;
})();
&#13;
: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);
}
&#13;
<div id="board" class="board"></div>
&#13;
&#13;
&#13;