<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>CodePen - Alphabet Speed Test </title>
  
  <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro" rel="stylesheet">
 <style>
 *,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  font-family: \'Source Sans Pro\', -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Oxygen, Ubuntu, Cantarell, \'Open Sans\', \'Helvetica Neue\', sans-serif;
}

body {
  align-items: center;
  background-color: #b24592;
  background-image: linear-gradient(166deg, blueviolet, darkcyan);
  display: flex;
  justify-content: center;
  margin: 0;
  min-height: 100vh;
  padding: 0;
}

.container {
  background-color: rgba(255, 255, 255, 0.25);
  border-radius: 8px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.15);
  max-width: 700px;
  padding: 2rem 3rem;
  width: 90%;
}

.game-container[data-state="pre-game"] .timer {
  opacity: 0;
}
.game-container[data-state="pre-game"] .restart-button, .game-container[data-state="pre-game"] .restart-button:hover, .game-container[data-state="pre-game"] .restart-button:focus {
  background-color: #fff;
  color: #333;
  opacity: .6;
}

.highscore-container {
  font-size: .9rem;
  margin: 1rem 0;
}

.timer {
  margin: 1rem 0;
  transition: opacity .1s ease-in-out;
}

.letter__container {
  display: flex;
  flex-wrap: wrap;
  margin-left: -.25rem;
  width: calc(100% + .5rem);
}

.letter {
  --background-color: rgba(255, 255, 255, .4);
  background-color: var(--background-color);
  border-radius: 3px;
  color: #333;
  display: block;
  font-size: 1.5rem;
  height: 2em;
  line-height: 2em;
  margin: .25rem;
  overflow: hidden;
  position: relative;
  text-align: center;
  text-transform: uppercase;
  width: 2em;
}
.letter[data-state=active]::before {
  transform: scaleX(1);
}
.letter::before {
  background-color: #fff;
  bottom: 0;
  content: \'\';
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  transform: scaleX(0);
  transform-origin: 0 center;
  transition: transform .1s ease-in-out;
}
.letter::after {
  content: attr(data-letter);
  position: relative;
}

.letter--template {
  display: none;
}

.restart-button__container {
  margin-top: 2rem;
  text-align: center;
}

.restart-button {
  background-color: #fff;
  border: 0;
  border-radius: 6px;
  color: #333;
  cursor: pointer;
  font-family: inherit;
  font-size: 1rem;
  padding: .5rem 2rem;
  transition: background-color .15s ease-in-out;
}
.restart-button:hover, .restart-button:focus {
  background-color: #f15f79;
  color: #ffffff;
}
 </style>

</head>
<body>

<div class="container">
  <div class="game-container" data-state="pre-game">
    <h1 class="title"></h1>
    <div class="highscore-container"></div>
    <div class="letter__container">
      <div class="letter letter--template" data-state="inactive"></div>
    </div>
    <div class="restart-button__container">
      <button class="restart-button" type="button">再玩一次</button>
    </div>
  </div>
</div>

<script>
const GameState = {
  PRE_GAME: \'pre-game\',
  RUNNING: \'running\',
  POST_GAME: \'post-game\'
};

const LetterState = {
  ACTIVE: \'active\',
  INACTIVE: \'inactive\'
};

class SpeedTest {  
  constructor(gameContainer, letterContainer) {
    this.letters = [];
    this.remainingLetters = [];
    this.state = GameState.PRE_GAME;
    this.timer = null;
    this.gameContainer = gameContainer;
    this.letterContainer = letterContainer;
    this.highscore = Infinity;
    this.onKeyDown = this.onKeyDown.bind(this);
    this.restartGame = this.restartGame.bind(this);
  };

  init(restart) {
    const availableLanguages = [\'en\', \'nb\', \'nn\', \'no\'];
    const preferredLanguage = SpeedTest.getPreferredLanguage(availableLanguages);
    this.letters = SpeedTest.getLetters(preferredLanguage);
    this.remainingLetters = this.letters;
    this.highscore = this.getHighscore();
    
    if (this.highscore && this.highscore !== Infinity) {
      this.updateHighscoreText(this.highscore);
    }

    const letterTemplate = this.letterContainer.querySelector(
      \'.letter--template\'
    );

    this.setTitle(\'按键盘上的A键启动,按空格键重新启动\');
    
    this.renderLetters(letterTemplate);

    if (!restart) {
      this.addEventListeners();
      this.getHighscore();
      
    }
  };
  static getPreferredLanguage(langs) {
    const defaultLang = \'en\';
    const navgLangs = navigator.languages;

    const preferredLang = navgLangs.filter(lang => langs.indexOf(lang) > -1)[0];

    return preferredLang || defaultLang;
  };
  static getLetters(preferredLang) {
    let letters = [];

    switch (preferredLang) {
      case \'nb\':
      case \'nn\':
      case \'no\':
        letters = [
          \'a\',
          \'b\',
          \'c\',
          \'d\',
          \'e\',
          \'f\',
          \'g\',
          \'h\',
          \'i\',
          \'j\',
          \'k\',
          \'l\',
          \'m\',
          \'n\',
          \'o\',
          \'p\',
          \'q\',
          \'r\',
          \'s\',
          \'t\',
          \'u\',
          \'v\',
          \'w\',
          \'x\',
          \'y\',
          \'z\',
          \'æ\',
          \'ø\',
          \'å\'
        ];
        break;
      default:
        letters = [
          \'a\',
          \'b\',
          \'c\',
          \'d\',
          \'e\',
          \'f\',
          \'g\',
          \'h\',
          \'i\',
          \'j\',
          \'k\',
          \'l\',
          \'m\',
          \'n\',
          \'o\',
          \'p\',
          \'q\',
          \'r\',
          \'s\',
          \'t\',
          \'u\',
          \'v\',
          \'w\',
          \'x\',
          \'y\',
          \'z\'
        ];
        break;
    }

    return letters;
  };
  renderLetters(template) {
    let letterElement;

    this.letters.forEach((letter, index) => {
      letterElement = template.cloneNode(true);
      letterElement.classList.remove(\'letter--template\');
      letterElement.dataset.letter = letter;
      letterElement.dataset.index = index;

      this.letterContainer.appendChild(letterElement);
    });

    // this.letterContainer.removeChild(template);
  };
  addEventListeners() {
    document.addEventListener(\'keydown\', this.onKeyDown, false);
    
    const restartButton = this.gameContainer.querySelector(\'.restart-button\');
    restartButton.addEventListener(\'click\', this.restartGame, false);
  };
  onKeyDown(event) {
    if (event.key === \' \') {
      
      this.restartGame();
    } else if (this.remainingLetters[0].toUpperCase() === event.key.toUpperCase()) {
      if (this.state === GameState.PRE_GAME) {
        this.startGame();
      }
      
      this.updateLetter(this.remainingLetters[0], LetterState.ACTIVE);
      this.remainingLetters = this.remainingLetters.slice(1);

      if (this.remainingLetters.length === 0) {
        this.stopGame();
      } else if (this.remainingLetters.length < this.letters.length / 5) {
        this.setTitle(\'只剩下几个了,继续!\');
      } else if (this.remainingLetters.length < this.letters.length / 2) {
        this.setTitle(\'过半了!\');
      }
    } else {
      const nextLetterElement = this.letterContainer.querySelector(
        `[data-state=${LetterState.INACTIVE}]`
      );
      this.wrongLetter(nextLetterElement);
    }
  };
  startGame() {
    this.gameContainer.dataset.state = GameState.RUNNING;
    this.state = GameState.RUNNING;
    this.setTitle(\'GO GO GO\');
    this.startTimer();
  };
  stopGame() {
    const t2 = this.stopTimer();
    const t1 = this.timer;
    this.gameContainer.dataset.state = GameState.POST_GAME;
    this.state = GameState.POST_GAME;

    let time = t2 - t1;
    time /= 1000;
    const timeString = this.formatTime(time);
    
    let newTitle = `您完成了! ✨ 时间是 ${timeString} 秒!`;
  
    if (this.highscore === null || time < this.highscore) {
      newTitle += \' 新纪录!\';
      this.highscore = time;
      this.updateHighscoreText(time);
      this.setHighscore(time);
    }

    this.setTitle(newTitle);
  };
  restartGame() {
    this.state = GameState.PRE_GAME;
    this.gameContainer.dataset.state = GameState.PRE_GAME;

    const letterElements = this.letterContainer.querySelectorAll(\'[data-letter]\');
    
    for (let i = 0; i < letterElements.length; i++) {
      this.letterContainer.removeChild(letterElements[i]);
    }
    
    this.init();
    
  };
  startTimer() {
    this.timer = performance.now();
  };
  stopTimer() {
    return performance.now();
  };
  wrongLetter(element) {
    if (!(\'animate\' in element)) {
      return;
    }

    const styles = getComputedStyle(element);
    const backgroundColor = styles.getPropertyValue(\'--background-color\');
    const errorRed = \'#f15f79\';

    const blinkAnimation = [
      {
        [\'--background-color\']: backgroundColor
      },
      {
        [\'--background-color\']: errorRed
      },
      {
        [\'--background-color\']: backgroundColor
      }
    ];

    const blinkTiming = {
      duration: 100,
      iterations: 1
    };

    element.animate(blinkAnimation, blinkTiming);
  };
  setTitle(text) {
    const title = this.gameContainer.querySelector(\'.title\');
    title.innerText = text;
  };
  updateLetter(letter, state) {
    const element = this.letterContainer.querySelector(
      `[data-letter=${letter}]`
    );
    element.dataset.state = state;
  };
  getHighscore() {    
    let highscore = Infinity;
    if (\'localStorage\' in window) {
      highscore = window.localStorage.getItem(\'highscore\');
    }
    
    if (highscore) {
      highscore = parseFloat(highscore);
    } else {
      highscore = Infinity;
    }
    
    return highscore;
  };
  setHighscore(highscore) {
    if (\'localStorage\' in window) {
      window.localStorage.setItem(\'highscore\', highscore);
    }
  };
  updateHighscoreText(newHighscore) {    
    const highscoreContainer = this.gameContainer.querySelector(
      \'.highscore-container\'
    );
    
    highscoreContainer.innerText = `个人最佳: ${this.formatTime(newHighscore)} 秒`;
  };
  formatTime(time) {
    return time.toLocaleString(undefined, {
      minimumFractionDigits: 2, 
      maximumFractionDigits: 2
    }); 
  }
}

const gameContainer = document.querySelector(\'.game-container\');
const letterContainer = document.querySelector(\'.letter__container\');
const game = new SpeedTest(gameContainer, letterContainer);
game.init();
</script>

</body>
</html>

 

版权声明:本文为xiewangfei123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xiewangfei123/p/13091010.html