通过javascript

时间:2016-11-09 21:36:56

标签: javascript addeventlistener

除了重新加载整个页面之外,如何通过单击开始按钮从头开始重新启动游戏? 出现此问题是因为当用户单击开始时调用了playGame函数,但是之前的playGame函数实例仍在运行。我甚至想过要杀死以前的函数实例,但是在JS中它除了使用webworker.terminate()之外无法实现。
这是代码:



document.addEventListener("DOMContentLoaded", function() {
  'use strict';

  var checkOn = document.querySelector("input[type=checkbox]");
  var gameCount = document.getElementsByClassName("innerCount")[0];
  var startButton = document.getElementById("innerStart");
  var strictButton = document.getElementById("strictButton");
  var strictInd = document.getElementById("strictIndicator");
  var strictMode = false;

  var soundArray = document.getElementsByTagName("audio");
  var buttons = document.querySelectorAll(".bigButton");
  var buttonArray = [].slice.call(buttons, 0);

  checkOn.addEventListener("change", function() {

    if (checkOn.checked) {
      gameCount.innerHTML = "--";
    } else {
      gameCount.innerHTML = "";
    }
  });

  strictButton.addEventListener("click", function() {
    if (checkOn.checked) {
      strictMode = !strictMode;
      strictMode ? strictInd.style.backgroundColor = "#FF0000" :
        strictInd.style.backgroundColor = "#850000";
    }
  });

  function getRandArray() {
    var array = [];
    for (var i = 0; i < 22; i++) {
      array[i] = Math.floor(Math.random() * 4);
    }
    return array;
  }

  startButton.addEventListener("click", function() {
    if (checkOn.checked) {
      var level = 0;
      var randIndexArr = getRandArray();
      sleep(700).then(function() {
        playGame(randIndexArr, level);
      });
    }
  });

  function sleep(time) {
    return new Promise(resolve => {
      setTimeout(resolve, time)
    })
  }

  function checkButton(randIndexArr, counter) {
    var indexButton = 0;
    var checker = function checker(e) {
      var clickedButtonId = e.target.dataset.sound;
      lightenButton(clickedButtonId);
      if (+(clickedButtonId) === randIndexArr[indexButton]) {
        if (indexButton === counter) {
          counter++;
          for (let i = 0; i < 4; i++) {
            buttonArray[i].removeEventListener("click", checker, false)
          }
          sleep(2000).then(function() {
            playGame(randIndexArr, counter);
          });
        }
        indexButton++;
      } else {
        gameCount.innerHTML = "--";
        if (strictMode) {
          indexButton = 0;
          counter = 0;
        } else {
          indexButton = 0;
        }
        for (let i = 0; i < 4; i++) {
          buttonArray[i].removeEventListener("click", checker, false)
        }
        sleep(2000).then(function() {
          playGame(randIndexArr, counter);
        });
      }
    };
    for (var i = 0; i < 4; i++) {
      buttonArray[i].addEventListener("click", checker, false)
    }
  }

  function playGame(randIndexArr, counter) {
    if (counter === 22) {
      return;
    }
    //Show the level of the Game
    gameCount.innerHTML = counter + 1;
    //Light and play user's input then check if input is correct
    randIndexArr.slice(0, counter + 1).reduce(function(promise, div, index) {
      return promise.then(function() {
        lightenButton(div);
        return new Promise(function(resolve, reject) {
          setTimeout(function() {
            resolve();
          }, 1000);
        })
      })
    }, Promise.resolve()).then(function() {
      checkButton(randIndexArr, counter);
    });
  }

  function lightenButton(id) {
    var lightColorsArr = ["liteGreen", "liteRed", "liteYell", "liteBlue"];
    soundArray[id].play();
    buttonArray[id].classList.add(lightColorsArr[id]);
    sleep(500).then(function() {
      buttonArray[id].classList.remove(lightColorsArr[id])
    });
  }
});
&#13;
@font-face {
  font-family: myDirector;
  src: url('https://raw.githubusercontent.com/Y-Taras/FreeCodeCamp/master/Simon/fonts/myDirector-Bold.otf');
}
body {
  background-color: #5f5f5f;
}
#outerCircle {
  display: flex;
  flex-wrap: wrap;
  margin: 0 auto;
  width: 560px;
  border: 2px dotted grey;
  position: relative;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.bigButton {
  height: 250px;
  width: 250px;
  border: solid #464646;
  transition: all 1s;
  -webkit-transition: all 1s;
  -moz-transition: all 1s;
  -o-transition: background-color 0.5s ease;
}
#greenButton {
  background-color: rgb(9, 174, 37);
  border-radius: 100% 0 0 0;
  border-width: 20px 10px 10px 20px;
}
.liteGreen#greenButton {
  background-color: #86f999;
}
#redButton {
  background-color: rgb(174, 9, 15);
  border-radius: 0 100% 0 0;
  border-width: 20px 20px 10px 10px;
}
.liteRed#redButton {
  background-color: #f9868a;
}
#yellowButton {
  background-color: rgb(174, 174, 9);
  border-radius: 0 0 0 100%;
  border-width: 10px 10px 20px 20px;
}
.liteYell#yellowButton {
  background-color: #f9f986;
}
#blueButton {
  background-color: rgb(9, 37, 174);
  border-radius: 0 0 100% 0;
  border-width: 10px 20px 20px 10px;
}
.liteBlue#blueButton {
  background-color: #8699f9;
}
div#innerCircle {
  border: 15px solid #464646;
  border-radius: 50%;
  position: absolute;
  top: 25%;
  right: 25%;
  background-color: #c4c7ce;
}
div.additionalBorder {
  margin: 4px;
  border-radius: 50%;
  height: 242px;
  width: 242px;
  overflow: hidden;
}
p#tradeMark {
  margin: auto;
  height: 104px;
  text-align: center;
  font-size: 68px;
  font-family: myDirector;
  color: #c4c7ce;
  background-color: black;
  border-color: antiquewhite;
  line-height: 162px;
}
span#reg {
  font-size: 12px;
}
.partition {
  height: 6px;
}
.buttons {
  height: 128px;
  border-radius: 0 0 128px 128px;
  border: 2px solid black;
}
/* Start and Strict buttons*/

table {
  margin-left: 5px;
}
td {
  text-align: center;
  width: auto;
  padding: 2px 10px;
  vertical-align: bottom;
}
div.innerCount {
  width: 54px;
  height: 40px;
  background-color: #34000e;
  color: crimson;
  border-radius: 11px;
  font-size: 28px;
  line-height: 42px;
  text-align: center;
  font-family: 'Segment7Standard', italic;
}
button#innerStart {
  width: 27px;
  height: 27px;
  border: 4px solid #404241;
  border-radius: 50%;
  background: #a50005;
  box-shadow: 0 0 3px gray;
  cursor: pointer;
}
div.strict {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
button#strictButton {
  width: 27px;
  height: 27px;
  border: 4px solid #404241;
  border-radius: 50%;
  background: yellow;
  box-shadow: 0 0 3px gray;
  cursor: pointer;
}
div#strictIndicator {
  width: 6px;
  height: 6px;
  margin-bottom: 2px;
  background-color: #850000;
  border-radius: 50%;
  border: 1px solid #5f5f5f;
}
#switcher {
  display: flex;
  justify-content: center;
  align-items: center;
}
.labels {
  font-family: 'Roboto', sans-serif;
  margin: 4px;
}
/* toggle switch */

.checkbox > input[type=checkbox] {
  visibility: hidden;
}
.checkbox {
  display: inline-block;
  position: relative;
  width: 60px;
  height: 30px;
  border: 2px solid #424242;
}
.checkbox > label {
  position: absolute;
  width: 30px;
  height: 26px;
  top: 2px;
  right: 2px;
  background-color: #a50005;
  cursor: pointer;
}
.checkbox > input[type=checkbox]:checked + label {
  right: 28px;
}
&#13;
<div id="outerCircle">
  <div class="bigButton" id="greenButton" data-sound="0">
    <audio src="https://s3.amazonaws.com/freecodecamp/simonSound1.mp3"></audio>
  </div>
  <div class="bigButton" id="redButton" data-sound="1">
    <audio src="https://s3.amazonaws.com/freecodecamp/simonSound2.mp3"></audio>
  </div>
  <div class="bigButton" id="yellowButton" data-sound="2">
    <audio src="https://s3.amazonaws.com/freecodecamp/simonSound3.mp3"></audio>
  </div>
  <div class="bigButton" id="blueButton" data-sound="3">
    <audio src="https://s3.amazonaws.com/freecodecamp/simonSound4.mp3"></audio>
  </div>
  <div id="innerCircle">
    <div class="additionalBorder">
      <p id="tradeMark">simon<span id="reg">&reg;</span>
      </p>
      <div class="partition"></div>
      <div class="buttons">
        <table>
          <tr class="firstRow">
            <td>
              <div class="innerCount"></div>
            </td>
            <td>
              <button type="button" id="innerStart"></button>
            </td>
            <td>
              <div class="strict">
                <div id="strictIndicator"></div>
                <button type="button" id="strictButton"></button>
              </div>
            </td>
          </tr>
          <tr class="labels">
            <td>
              <div id="countLabel">COUNT</div>
            </td>
            <td>
              <div id="startLabel">START</div>
            </td>
            <td>
              <div id="strictLabel">STRICT</div>
            </td>
          </tr>
        </table>
        <div id="switcher">
          <span class="labels">ON</span>
          <div class="checkbox">
            <input id="checkMe" type="checkbox">
            <label for="checkMe"></label>
          </div>
          <span class="labels">OFF</span>
        </div>
      </div>
    </div>
  </div>
</div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

我没有深入挖掘你的代码,但看起来它的关键是你正在使用setTimeout(),并且当你重新启动时,超时可能仍在运行。

您需要做的是存储setTimeout()的返回值,该值实际上是您可以传递给clearTimeout()的ID,这将停止超时。

因此,在sleep()函数上,存储id:

function sleep(time) {
   return new Promise(resolve => {
     this.timeoutId = setTimeout(resolve, time)
   });
}

当你重新开始游戏时:

// ...
if (this.timeoutId) {
    clearTimeout(this.timeoutId);
    this.timeoutId = null;
}
//...

然后还要确保你没有任何其他代码可以同时运行超过两个超时(或者你将丢失其中一个ID)。