【问题标题】:Why event listeners are not getting removed为什么事件侦听器没有被删除
【发布时间】:2020-05-27 07:12:52
【问题描述】:

document.getElementsByClassName('restart')[0].addEventListener('click', init);
var tiles = document.querySelectorAll('.row div');
let bombTile = [];

init();


 function clickHand(tile, index) {
    if (bombTile.indexOf(index) !== -1) {
        bombClicked(tile , index);
    } else {
        flipMe(tile, index);
    }
}


function bombClicked(tile ,index) {
    tile.classList.add('bomb');
    bombTile.forEach(e => {
        tiles[e].classList.add('bomb');
        tiles[e].innerHTML = '<i class="fas fa-bomb"></i>';
    })
    document.getElementsByClassName('row')[0].classList.add('bombed');
    
}

function flipMe(tile , index) {
    tile.classList.add('active');
    tile.innerHTML = '<i class="fas fa-sun"></i>';
    tile.removeEventListener('click' , clickHand);
}


function init() {
    bombTile = []
    while (bombTile.length < 10) {
        var r = Math.floor(Math.random() * 80) + 1;
        if (bombTile.indexOf(r) === -1) bombTile.push(r);
    }
    document.getElementsByClassName('row')[0].classList.remove('bombed')
    tiles.forEach((tile, index) => {
        tile.addEventListener('click',  clickHand.bind(this,tile , index));
        tile.className = '';
        tile.innerHTML = '';

    })
}
*{
    padding: 0;
    margin: 0;
}

body{
    display: flex;
    justify-content: center;
    flex-direction: column;
    background-image: linear-gradient(to right, rgba(233,233,233,.9), rgba(0,0,0,.8)) , url("https://images5.alphacoders.com/540/thumb-1920-540654.jpg");
    background-size: cover;
    align-items: center;
    font-family: 'Montserrat', sans-serif;
    min-height: 100vh;
}

.row{
    width: 540px;
    display: flex;
    flex-wrap: wrap;
    box-shadow:0 2px 4px rgba(0,0,0,.8);
}

.row.bombed{
    animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
    transform: translate3d(0, 0, 0);
    backface-visibility: hidden;
}

h1{
    margin-bottom: 20px;
    font-weight: 300;
}

.row div{
    display: flex;
    justify-content: center;
    box-sizing: border-box;
    align-items: center;
    width: 60px;
    height: 60px;
    background: rgba(200,200,200,.8);
    border: 1px solid #000;

    transition: all .3s ease;

}

.row div.active{
    transform: rotateY(180deg);
    background-color: #000;
}

.row div.active i{
    color: yellow;
    font-size: 30px;
}

.row div.bomb{
    transform: rotateY(180deg);
    background: #f00;
    font-size: 20px;
}


.restart:link,
.restart:visited{
    text-decoration: none;
    text-transform: uppercase;
    padding: 10px 15px;
    display: inline-block;
    margin: 20px 0;
    border: 1px solid #fff;
    color: white;
    transition: all .3s ease;
}

.restart:hover{
    border: 1px solid #fff;
    background-color: white;
    color: black;
}

@keyframes shake {
    10%, 90% {
      transform: translate3d(-1px, 0, 0);
    }
    
    20%, 80% {
      transform: translate3d(2px, 0, 0);
    }
  
    30%, 50%, 70% {
      transform: translate3d(-4px, 0, 0);
    }
  
    40%, 60% {
      transform: translate3d(4px, 0, 0);
    }
  }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bomber</title>
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
    <script src="https://kit.fontawesome.com/f80fd99102.js" crossorigin="anonymous"></script>
</head>
<body> 
    <h1>
        Bomber
    </h1>
    <div class="bomber-grid">
        <div class="row">
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>
    <a href="#!" class="restart">
        New Game
    </a>
    <script src="index.js"></script>
</body>
</html>

这是一个简单的轰炸游戏,其中 10 个瓷砖有炸弹。一旦用户点击炸弹游戏结束。

我的问题是当我点击任何磁贴时,我想删除附加到它的事件监听。如果用户单击有炸弹的图块,我想从每个图块中删除事件侦听器。

我添加了删除事件侦听器的代码,但它无法正常工作。

【问题讨论】:

    标签: javascript html css dom-events


    【解决方案1】:

    要删除事件侦听器,您必须将 same 函数传递给您传递给 addEventListenerremoveEventListener

    tile.removeEventListener('click' , clickHand);
    
    tile.addEventListener('click',  clickHand.bind(this,tile , index));
    

    您正在尝试删除 clickHand,但您添加了一个 函数,该函数是通过在 clickHand 上调用 bind 生成的。


    对此更简单的方法可能是更改clickHand,以便检查磁贴的状态并确定它是否已被点击(如果有,则不做任何其他操作就返回)。

    【讨论】:

      【解决方案2】:

      removeListener 可能不起作用的原因是您每次使用.bind 时都在创建一个新函数。 removeEventListener 期望使用与 addEventListener 中的处理程序相同的函数。

      你正在做的是,

      tile.addEventListener('click',  clickHand.bind(this,tile , index));
      

      所以你不能使用删除

      tile.removeEventListener('click',  clickHand);
      

      要正确删除它,请执行以下操作,

      let tileHandler =  clickHand.bind(this,tile , index)
      tile.addEventListener('click',  tileHandler);
      
      // Then remove by
      tile.removeEventListener('click',  tileHandler);
      

      但是有很多图块,您必须为每个创建的新处理程序保留记录。所以你能做的就是为游戏是否结束设置一个标志。如果是,则防止瓷砖翻转。

      添加标志

      let gameOver;
      

      在您的点击功能中

      else if(!gameOver){
              flipMe(tile, index);
          }
      }
      

      并在您的bombClicked() 函数中添加,

      gameOver=true;
      

      document.getElementsByClassName('restart')[0].addEventListener('click', init);
      var tiles = document.querySelectorAll('.row div');
      let bombTile = [];
      let gameOver = false;
      init();
      
      
       function clickHand(tile, index) {
          if (bombTile.indexOf(index) !== -1) {
              bombClicked(tile , index);
          } else if(!gameOver){
              flipMe(tile, index);
          }
      }
      
      
      function bombClicked(tile ,index) {
          gameOver=true;
          tile.classList.add('bomb');
          bombTile.forEach(e => {
              tiles[e].classList.add('bomb');
              tiles[e].innerHTML = '<i class="fas fa-bomb"></i>';
          })
          document.getElementsByClassName('row')[0].classList.add('bombed');
          
      }
      
      function flipMe(tile , index) {
          tile.classList.add('active');
          tile.innerHTML = '<i class="fas fa-sun"></i>';
          tile.removeEventListener('click' , clickHand);
      }
      
      
      function init() {
          bombTile = []
          while (bombTile.length < 10) {
              var r = Math.floor(Math.random() * 80) + 1;
              if (bombTile.indexOf(r) === -1) bombTile.push(r);
          }
          document.getElementsByClassName('row')[0].classList.remove('bombed')
          tiles.forEach((tile, index) => {
              tile.addEventListener('click',  clickHand.bind(this,tile , index));
              tile.className = '';
              tile.innerHTML = '';
      
          })
      }
      *{
          padding: 0;
          margin: 0;
      }
      
      body{
          display: flex;
          justify-content: center;
          flex-direction: column;
          background-image: linear-gradient(to right, rgba(233,233,233,.9), rgba(0,0,0,.8)) , url("https://images5.alphacoders.com/540/thumb-1920-540654.jpg");
          background-size: cover;
          align-items: center;
          font-family: 'Montserrat', sans-serif;
          min-height: 100vh;
      }
      
      .row{
          width: 540px;
          display: flex;
          flex-wrap: wrap;
          box-shadow:0 2px 4px rgba(0,0,0,.8);
      }
      
      .row.bombed{
          animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
          transform: translate3d(0, 0, 0);
          backface-visibility: hidden;
      }
      
      h1{
          margin-bottom: 20px;
          font-weight: 300;
      }
      
      .row div{
          display: flex;
          justify-content: center;
          box-sizing: border-box;
          align-items: center;
          width: 60px;
          height: 60px;
          background: rgba(200,200,200,.8);
          border: 1px solid #000;
      
          transition: all .3s ease;
      
      }
      
      .row div.active{
          transform: rotateY(180deg);
          background-color: #000;
      }
      
      .row div.active i{
          color: yellow;
          font-size: 30px;
      }
      
      .row div.bomb{
          transform: rotateY(180deg);
          background: #f00;
          font-size: 20px;
      }
      
      
      .restart:link,
      .restart:visited{
          text-decoration: none;
          text-transform: uppercase;
          padding: 10px 15px;
          display: inline-block;
          margin: 20px 0;
          border: 1px solid #fff;
          color: white;
          transition: all .3s ease;
      }
      
      .restart:hover{
          border: 1px solid #fff;
          background-color: white;
          color: black;
      }
      
      @keyframes shake {
          10%, 90% {
            transform: translate3d(-1px, 0, 0);
          }
          
          20%, 80% {
            transform: translate3d(2px, 0, 0);
          }
        
          30%, 50%, 70% {
            transform: translate3d(-4px, 0, 0);
          }
        
          40%, 60% {
            transform: translate3d(4px, 0, 0);
          }
        }
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Bomber</title>
          <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
          <link rel="stylesheet" href="style.css">
          <script src="https://kit.fontawesome.com/f80fd99102.js" crossorigin="anonymous"></script>
      </head>
      <body> 
          <h1>
              Bomber
          </h1>
          <div class="bomber-grid">
              <div class="row">
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
              </div>
          </div>
          <a href="#!" class="restart">
              New Game
          </a>
          <script src="index.js"></script>
      </body>
      </html>

      【讨论】: