一个菜鸟的互联网技术分享博客
您的位置: 主页 > 英文字母打字速度测试游戏
advertisement

英文字母打字速度测试游戏

代码如下:
  1. <!DOCTYPE html>  
  2. <html lang="en" >  
  3. <head>  
  4.   <meta charset="UTF-8">  
  5.   <title>CodePen - Alphabet Speed Test </title>  
  6.     
  7.   <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro" rel="stylesheet">  
  8.  <style>  
  9.  *,  
  10. *::before,  
  11. *::after {  
  12.   box-sizing: border-box;  
  13. }  
  14.   
  15. html {  
  16.   font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;  
  17. }  
  18.   
  19. body {  
  20.   align-items: center;  
  21.   background-color: #b24592;  
  22.   background-image: linear-gradient(166deg, blueviolet, darkcyan);  
  23.   display: flex;  
  24.   justify-content: center;  
  25.   margin: 0;  
  26.   min-height: 100vh;  
  27.   padding: 0;  
  28. }  
  29.   
  30. .container {  
  31.   background-color: rgba(2552552550.25);  
  32.   border-radius: 8px;  
  33.   box-shadow: 0 1px 6px rgba(0000.15);  
  34.   max-width: 700px;  
  35.   padding: 2rem 3rem;  
  36.   width: 90%;  
  37. }  
  38.   
  39. .game-container[data-state="pre-game"] .timer {  
  40.   opacity: 0;  
  41. }  
  42. .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 {  
  43.   background-color: #fff;  
  44.   color: #333;  
  45.   opacity: .6;  
  46. }  
  47.   
  48. .highscore-container {  
  49.   font-size: .9rem;  
  50.   margin: 1rem 0;  
  51. }  
  52.   
  53. .timer {  
  54.   margin: 1rem 0;  
  55.   transition: opacity .1s ease-in-out;  
  56. }  
  57.   
  58. .letter__container {  
  59.   display: flex;  
  60.   flex-wrap: wrap;  
  61.   margin-left: -.25rem;  
  62.   width: calc(100% + .5rem);  
  63. }  
  64.   
  65. .letter {  
  66.   --background-color: rgba(255255255, .4);  
  67.   background-color: var(--background-color);  
  68.   border-radius: 3px;  
  69.   color: #333;  
  70.   display: block;  
  71.   font-size: 1.5rem;  
  72.   height: 2em;  
  73.   line-height: 2em;  
  74.   margin: .25rem;  
  75.   overflow: hidden;  
  76.   position: relative;  
  77.   text-align: center;  
  78.   text-transform: uppercase;  
  79.   width: 2em;  
  80. }  
  81. .letter[data-state=active]::before {  
  82.   transform: scaleX(1);  
  83. }  
  84. .letter::before {  
  85.   background-color: #fff;  
  86.   bottom: 0;  
  87.   content: '';  
  88.   left: 0;  
  89.   position: absolute;  
  90.   right: 0;  
  91.   top: 0;  
  92.   transform: scaleX(0);  
  93.   transform-origin: 0 center;  
  94.   transition: transform .1s ease-in-out;  
  95. }  
  96. .letter::after {  
  97.   content: attr(data-letter);  
  98.   position: relative;  
  99. }  
  100.   
  101. .letter--template {  
  102.   display: none;  
  103. }  
  104.   
  105. .restart-button__container {  
  106.   margin-top: 2rem;  
  107.   text-align: center;  
  108. }  
  109.   
  110. .restart-button {  
  111.   background-color: #fff;  
  112.   border: 0;  
  113.   border-radius: 6px;  
  114.   color: #333;  
  115.   cursor: pointer;  
  116.   font-family: inherit;  
  117.   font-size: 1rem;  
  118.   padding: .5rem 2rem;  
  119.   transition: background-color .15s ease-in-out;  
  120. }  
  121. .restart-button:hover, .restart-button:focus {  
  122.   background-color: #f15f79;  
  123.   color: #ffffff;  
  124. }  
  125.  </style>  
  126.   
  127. </head>  
  128. <body>  
  129.   
  130. <div class="container">  
  131.   <div class="game-container" data-state="pre-game">  
  132.     <h1 class="title"></h1>  
  133.     <div class="highscore-container"></div>  
  134.     <div class="letter__container">  
  135.       <div class="letter letter--template" data-state="inactive"></div>  
  136.     </div>  
  137.     <div class="restart-button__container">  
  138.       <button class="restart-button" type="button">再玩一次</button>  
  139.     </div>  
  140.   </div>  
  141. </div>  
  142.   
  143. <script>  
  144. const GameState = {  
  145.   PRE_GAME: 'pre-game',  
  146.   RUNNING: 'running',  
  147.   POST_GAME: 'post-game'  
  148. };  
  149.   
  150. const LetterState = {  
  151.   ACTIVE: 'active',  
  152.   INACTIVE: 'inactive'  
  153. };  
  154.   
  155. class SpeedTest {    
  156.   constructor(gameContainer, letterContainer) {  
  157.     this.letters = [];  
  158.     this.remainingLetters = [];  
  159.     this.state = GameState.PRE_GAME;  
  160.     this.timer = null;  
  161.     this.gameContainer = gameContainer;  
  162.     this.letterContainer = letterContainer;  
  163.     this.highscore = Infinity;  
  164.     this.onKeyDown = this.onKeyDown.bind(this);  
  165.     this.restartGame = this.restartGame.bind(this);  
  166.   };  
  167.   
  168.   init(restart) {  
  169.     const availableLanguages = ['en', 'nb', 'nn', 'no'];  
  170.     const preferredLanguage = SpeedTest.getPreferredLanguage(availableLanguages);  
  171.     this.letters = SpeedTest.getLetters(preferredLanguage);  
  172.     this.remainingLetters = this.letters;  
  173.     this.highscore = this.getHighscore();  
  174.       
  175.     if (this.highscore && this.highscore !== Infinity) {  
  176.       this.updateHighscoreText(this.highscore);  
  177.     }  
  178.   
  179.     const letterTemplate = this.letterContainer.querySelector(  
  180.       '.letter--template'  
  181.     );  
  182.   
  183.     this.setTitle('按键盘上的A键启动,按空格键重新启动');  
  184.       
  185.     this.renderLetters(letterTemplate);  
  186.   
  187.     if (!restart) {  
  188.       this.addEventListeners();  
  189.       this.getHighscore();  
  190.         
  191.     }  
  192.   };  
  193.   static getPreferredLanguage(langs) {  
  194.     const defaultLang = 'en';  
  195.     const navgLangs = navigator.languages;  
  196.   
  197.     const preferredLang = navgLangs.filter(lang => langs.indexOf(lang) > -1)[0];  
  198.   
  199.     return preferredLang || defaultLang;  
  200.   };  
  201.   static getLetters(preferredLang) {  
  202.     let letters = [];  
  203.   
  204.     switch (preferredLang) {  
  205.       case 'nb':  
  206.       case 'nn':  
  207.       case 'no':  
  208.         letters = [  
  209.           'a',  
  210.           'b',  
  211.           'c',  
  212.           'd',  
  213.           'e',  
  214.           'f',  
  215.           'g',  
  216.           'h',  
  217.           'i',  
  218.           'j',  
  219.           'k',  
  220.           'l',  
  221.           'm',  
  222.           'n',  
  223.           'o',  
  224.           'p',  
  225.           'q',  
  226.           'r',  
  227.           's',  
  228.           't',  
  229.           'u',  
  230.           'v',  
  231.           'w',  
  232.           'x',  
  233.           'y',  
  234.           'z',  
  235.           'æ',  
  236.           'ø',  
  237.           'å'  
  238.         ];  
  239.         break;  
  240.       default:  
  241.         letters = [  
  242.           'a',  
  243.           'b',  
  244.           'c',  
  245.           'd',  
  246.           'e',  
  247.           'f',  
  248.           'g',  
  249.           'h',  
  250.           'i',  
  251.           'j',  
  252.           'k',  
  253.           'l',  
  254.           'm',  
  255.           'n',  
  256.           'o',  
  257.           'p',  
  258.           'q',  
  259.           'r',  
  260.           's',  
  261.           't',  
  262.           'u',  
  263.           'v',  
  264.           'w',  
  265.           'x',  
  266.           'y',  
  267.           'z'  
  268.         ];  
  269.         break;  
  270.     }  
  271.   
  272.     return letters;  
  273.   };  
  274.   renderLetters(template) {  
  275.     let letterElement;  
  276.   
  277.     this.letters.forEach((letter, index) => {  
  278.       letterElement = template.cloneNode(true);  
  279.       letterElement.classList.remove('letter--template');  
  280.       letterElement.dataset.letter = letter;  
  281.       letterElement.dataset.index = index;  
  282.   
  283.       this.letterContainer.appendChild(letterElement);  
  284.     });  
  285.   
  286.     // this.letterContainer.removeChild(template);  
  287.   };  
  288.   addEventListeners() {  
  289.     document.addEventListener('keydown', this.onKeyDown, false);  
  290.       
  291.     const restartButton = this.gameContainer.querySelector('.restart-button');  
  292.     restartButton.addEventListener('click', this.restartGame, false);  
  293.   };  
  294.   onKeyDown(event) {  
  295.     if (event.key === ' ') {  
  296.         
  297.       this.restartGame();  
  298.     } else if (this.remainingLetters[0].toUpperCase() === event.key.toUpperCase()) {  
  299.       if (this.state === GameState.PRE_GAME) {  
  300.         this.startGame();  
  301.       }  
  302.         
  303.       this.updateLetter(this.remainingLetters[0], LetterState.ACTIVE);  
  304.       this.remainingLetters = this.remainingLetters.slice(1);  
  305.   
  306.       if (this.remainingLetters.length === 0) {  
  307.         this.stopGame();  
  308.       } else if (this.remainingLetters.length < this.letters.length / 5) {  
  309.         this.setTitle('只剩下几个了,继续!');  
  310.       } else if (this.remainingLetters.length < this.letters.length / 2) {  
  311.         this.setTitle('过半了!');  
  312.       }  
  313.     } else {  
  314.       const nextLetterElement = this.letterContainer.querySelector(  
  315.         `[data-state=${LetterState.INACTIVE}]`  
  316.       );  
  317.       this.wrongLetter(nextLetterElement);  
  318.     }  
  319.   };  
  320.   startGame() {  
  321.     this.gameContainer.dataset.state = GameState.RUNNING;  
  322.     this.state = GameState.RUNNING;  
  323.     this.setTitle('GO GO GO');  
  324.     this.startTimer();  
  325.   };  
  326.   stopGame() {  
  327.     const t2 = this.stopTimer();  
  328.     const t1 = this.timer;  
  329.     this.gameContainer.dataset.state = GameState.POST_GAME;  
  330.     this.state = GameState.POST_GAME;  
  331.   
  332.     let time = t2 - t1;  
  333.     time /= 1000;  
  334.     const timeString = this.formatTime(time);  
  335.       
  336.     let newTitle = `您完成了! ✨ 时间是 ${timeString} 秒!`;  
  337.     
  338.     if (this.highscore === null || time < this.highscore) {  
  339.       newTitle += ' 新纪录!';  
  340.       this.highscore = time;  
  341.       this.updateHighscoreText(time);  
  342.       this.setHighscore(time);  
  343.     }  
  344.   
  345.     this.setTitle(newTitle);  
  346.   };  
  347.   restartGame() {  
  348.     this.state = GameState.PRE_GAME;  
  349.     this.gameContainer.dataset.state = GameState.PRE_GAME;  
  350.   
  351.     const letterElements = this.letterContainer.querySelectorAll('[data-letter]');  
  352.       
  353.     for (let i = 0; i < letterElements.length; i++) {  
  354.       this.letterContainer.removeChild(letterElements[i]);  
  355.     }  
  356.       
  357.     this.init();  
  358.       
  359.   };  
  360.   startTimer() {  
  361.     this.timer = performance.now();  
  362.   };  
  363.   stopTimer() {  
  364.     return performance.now();  
  365.   };  
  366.   wrongLetter(element) {  
  367.     if (!('animate' in element)) {  
  368.       return;  
  369.     }  
  370.   
  371.     const styles = getComputedStyle(element);  
  372.     const backgroundColor = styles.getPropertyValue('--background-color');  
  373.     const errorRed = '#f15f79';  
  374.   
  375.     const blinkAnimation = [  
  376.       {  
  377.         ['--background-color']: backgroundColor  
  378.       },  
  379.       {  
  380.         ['--background-color']: errorRed  
  381.       },  
  382.       {  
  383.         ['--background-color']: backgroundColor  
  384.       }  
  385.     ];  
  386.   
  387.     const blinkTiming = {  
  388.       duration: 100,  
  389.       iterations: 1  
  390.     };  
  391.   
  392.     element.animate(blinkAnimation, blinkTiming);  
  393.   };  
  394.   setTitle(text) {  
  395.     const title = this.gameContainer.querySelector('.title');  
  396.     title.innerText = text;  
  397.   };  
  398.   updateLetter(letter, state) {  
  399.     const element = this.letterContainer.querySelector(  
  400.       `[data-letter=${letter}]`  
  401.     );  
  402.     element.dataset.state = state;  
  403.   };  
  404.   getHighscore() {      
  405.     let highscore = Infinity;  
  406.     if ('localStorage' in window) {  
  407.       highscore = window.localStorage.getItem('highscore');  
  408.     }  
  409.       
  410.     if (highscore) {  
  411.       highscore = parseFloat(highscore);  
  412.     } else {  
  413.       highscore = Infinity;  
  414.     }  
  415.       
  416.     return highscore;  
  417.   };  
  418.   setHighscore(highscore) {  
  419.     if ('localStorage' in window) {  
  420.       window.localStorage.setItem('highscore', highscore);  
  421.     }  
  422.   };  
  423.   updateHighscoreText(newHighscore) {      
  424.     const highscoreContainer = this.gameContainer.querySelector(  
  425.       '.highscore-container'  
  426.     );  
  427.       
  428.     highscoreContainer.innerText = `个人最佳: ${this.formatTime(newHighscore)} 秒`;  
  429.   };  
  430.   formatTime(time) {  
  431.     return time.toLocaleString(undefined, {  
  432.       minimumFractionDigits: 2,   
  433.       maximumFractionDigits: 2  
  434.     });   
  435.   }  
  436. }  
  437.   
  438. const gameContainer = document.querySelector('.game-container');  
  439. const letterContainer = document.querySelector('.letter__container');  
  440. const game = new SpeedTest(gameContainer, letterContainer);  
  441. game.init();  
  442. </script>  
  443.   
  444. </body>  
  445. </html>

zhangren.online
上一篇:三种原生JS实现数字从0自动增加到某个指定的数字
下一篇:没有了

您可能喜欢

​爱心鱼游戏

​爱心鱼游戏

​幸福摩天轮

​幸福摩天轮

​英文字母打字速度测试游戏

​英文字母打字速度测试游戏

回到顶部