@IckiSanZ

Как реализовать клавиатурный тренажер на JavaScript + помощь с функцией?

Здравствуйте, давайте опишу ситуацию для понимая общей картины. Проходил я мини-курс по JS в компьютерной академии, но за то время, которое нам выделили на него, учитель успел нам объяснить только азы языка. Я для себя почитал конечно, но узнал честно говоря не намного больше (все еще в процессе изучения). И вот настал день, когда нужно делать проект на экзамен. Я загорелся идеей сделать простенький клавиатурный тренажер (пример: vse10.ru) и не так что уж совсем по быдлокодерски, а красиво с одной функцией, в которую нужно передать текст уровня, который впоследствии будет вводить пользователь, и все. Работать все должно примерно так: на экране высвечиваются буквы, которые пользователь должен ввести и по нажатию нужных клавиш (keypress) они будут просто менять цвет. С CSS частью я и сам справлюсь, а вот с обработкой событий, мне понадобится помощь. Я уже написал кое-что, но ввиду малого количества знаний и опыта, результат... а что говорить, вот он:
let mistakesCounter = 0;

function checkUsersKey (levelText) {
  var theEnd = false;
  var counterLetters = 0;
  var keyName;
  
  function checkKeyEvent(event) {
    //keyName = getChar(event);
    if(theEnd) {
        document.removeEventListener('keypress', checkKeyEvent);
        return;
    }
    while (counterLetters < levelText.length) {
	    keyName = getChar(event);
	    if(levelText[counterLetters] == keyName){
	        alert("Проверка 1 (значение true): работает"); //просто проверка
	        counterLetters++;
	        //тут будет код, который меняет css буквы
	    } else if (keyName == null) {
	    	//do nothing
	    	alert("Проверка 2")
	    } else {
	    	alert("Проверка 3 (else): работает");
	    	//тут будет код, оповещающий о том, что пользователь допустил ошибку
	    	mistakesCounter++;
	    }
	}
    theEnd = true;
  }
  while(counterLetters < levelText.length) {
  	document.addEventListener("keypress", checkKeyEvent);
  }
}
checkUsersKey("something");

Как видите, код написан так, что в keyName значение записывается только один раз, а как дальше у меня даже идей нет.
Буду благодарен, если вы поможете с функцией (мне нужно что-бы каждую итерацию цикла keyName получала новое значение от пользователя, ну и соответственно выполнялся цикл.
"Благодарен за любую помощь" -Быдлокодер Владислав
  • Вопрос задан
  • 1120 просмотров
Решения вопроса 1
@IckiSanZ Автор вопроса
Уже решил проблему. Вот код:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Typer</title>
		<link rel="stylesheet" type="text/css" href="style.css">
		<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro" rel="stylesheet">
		<link href="https://fonts.googleapis.com/css?family=PT+Sans+Narrow" rel="stylesheet">
	</head>
	<body id="body">
		<div id="main"><b><div id="mistakes"></div></b><div id="alertText"></div><div id="field"><span id="text"></span></div></div>
		<script type="text/javascript" src="script.js"></script>
	</body>
</html>


body {
	margin: 0px;
	background-color: #4BABE7;
}

#main {
	width: 1366px;
	height: 510px;
	background-color: #4BABE7;
}

#field {
	background-color: white;
	margin-left: 150px;
	margin-right: 150px;
	border-radius: 20px;
	transform: translate(0, 110px);
	padding-top: 30px;
	padding-bottom: 30px;
	padding-right: 40px;
	padding-left: 40px;
}
#text {
	font-family: 'Source Sans Pro', sans-serif;
	font-size: 18pt;
}

#mistakes {
	font-family: 'PT Sans Narrow', sans-serif;
	text-decoration: underline;
	color: white;
	font-size: 13pt;
	transform: translate(170px, 105px); 
}

#alertText {
	color: red;
	font-family: 'Source Sans Pro', sans-serif;
	font-size: 19pt;
}


// event.type должен быть keypress
function getChar(event) {
  if (event.which == null) { // IE
    if (event.keyCode < 32) return null; // спец. символ
    return String.fromCharCode(event.keyCode)
  }

  if (event.which != 0 && event.charCode != 0) { // все кроме IE
    if (event.which < 32) return null; // спец. символ
    return String.fromCharCode(event.which); // остальные
  }

  return null; // спец. символ
}

var counterLetters = 0;
var levelText= "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur posuere tellus et leo mollis, vel"; //текст, который будет вводить пользователь
text.innerHTML=levelText;
let mistakesCounter = 0; //Счетчик ошибок
mistakes.innerHTML = ("Кол-во ошибок: " + mistakesCounter);
function checkKeyEvent() {
  	var keyName = getChar(event);
  	if(levelText[counterLetters] == keyName){
	        console.log("Введен символ"); //просто проверка
	        levelText = levelText.substring(1);
	        text.innerHTML = levelText;

	    } else if (keyName == null) {
	    	//do nothing
	    	 console.log("Нажата спец. клавиша");
	    	 alertText.innerHTML =("Нажата спец. клавиша");
	    	 
	    } else {
	    	console.log("Введен неверный символ");
	    	//тут будет код, оповещающий об ошибке
	    	mistakesCounter++;
	    	mistakes.innerHTML = ("Кол-во ошибок: " + mistakesCounter);
	    }

}
document.addEventListener("keypress", checkKeyEvent);
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Vlad_IT
@Vlad_IT Куратор тега JavaScript
Front-end разработчик
Вы немного не понимаете, как работают события (судя по этому, и предыдущему вопросу). Грубо говоря, метод document.addEventListener("keypress", checkKeyEvent) создает событие нажатия на клавишу клавиатуры, которое будет выполнять переданную функцию. Если нажать клавишу, то выполняется событие keypress, которое выполнит функцию checkKeyEvent, в которую передается объект события (а в нем и нажатая клавиша).
Не нужно вызывать добавление события в цикле, вызовете один раз, и уже в функции checkKeyEvent делайте проверку.
function checkKeyEvent(event) {
     // При нажатии на клавишу выполняется эта функция. Каждый раз.
}
document.addEventListener("keypress", checkKeyEvent);

Ваш цикл while(counterLetters < levelText.length) { будет бесконечным, т.к. значение levelText или counterLetters не меняются. Даже если бы он не был вечен, он бы породил множество обработчиков событий, а нам нужно только одно. Циклы тут вообще не нужны. Вот такой код. Постарался подробно прокомментировать.
let mistakesCounter = 0;
// Это ваша getChar. Не знаю точно, такая же реализация, но это довольно известный код
function getChar(event) {
    if (event.which == null) { // IE
        if (event.keyCode < 32) return null; // спец. символ
        return String.fromCharCode(event.keyCode)
    }

    if (event.which != 0 && event.charCode != 0) { // все кроме IE
        if (event.which < 32) return null; // спец. символ
        return String.fromCharCode(event.which); // остальные
    }

    return null; // спец. символ
}

function checkUsersKey(levelText) {
    var theEnd = false;
    var counterLetters = 0;
    var keyName;

    function checkKeyEvent(event) {
        // Делаем проверку, если текущий символ равен длинне символов...
        if (counterLetters >= levelText.length) {
            // То удаляем обработку события чтобы завершить печатанье.
            document.removeEventListener('keypress', checkKeyEvent);
            // Тут можете вывести сообщение пользователю, что задание закончено
            return;
        }
        keyName = getChar(event);
        // Это ваш код, проверяет, правильно ли пользователь ввел
        if (levelText[counterLetters] == keyName) {
            alert("Проверка 1 (значение true): работает"); //просто проверка
            counterLetters++;
            //тут будет код, который меняет css буквы
        } else if (keyName == null) {
            //do nothing
            alert("Проверка 2")
        } else {
            alert("Проверка 3 (else): работает");
            //тут будет код, оповещающий о том, что пользователь допустил ошибку
            mistakesCounter++;
        }
    }
    // Добавляем обработку события нажатия клавиши на функцию checkKeyEvent
    // Добавляем только один раз, она будет вызывать checkKeyEvent после каждого нажатия и удержания клавиши
    document.addEventListener("keypress", checkKeyEvent);
}
checkUsersKey("something");
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы