Tabla de contenido
Una vez más aquí. En el siguiente artículo vamos a ver algo que un usuario me ha pedido, y que yo tenía descargado en un disco duro desde hace ya algún tiempo. Se trata de un cuestionario con temporizador para que el usuario responda ciertas preguntas y cuente las respuestas correctas. Este código como digo, lo tenía yo en un disco duro, pues lo descargué de algún sitio web (no recuerdo cual) hace ya un tiempo.
Tras probarlo, y ver que sigue funcionando correctamente, lo voy a dejar aquí publicado para que el usuario que me preguntó cómo podría hacerlo, pueda tener una base por la que empezar. Para realizar este cuestionario necesitaremos utilizar un poco de HTML, CSS para darle una presentación interesante y JavaScript para que el cuestionario haga lo que tiene que hacer.
Un vistazo rápido al funcionamiento del cuestionario con temporizador
Esta aplicación consta de tres cuadros. Al principio, en la página web, se muestra un botón etiquetado como ‘Empezar el cuestionario‘. Cuando se hace clic en ese botón, aparecerá en pantalla un cuadro de información con las cinco cosas a tener en cuenta cuando se inicia el cuestionario.
Como decía, en este cuadro de información, hay algunas reglas del cuestionario y dos botones etiquetados como ‘Salir’ y ‘Continuar’. Si se hace clic en el botón Salir, el cuadro de información se ocultará. En caso de hacer clic en el botón de Continuar, aparecerá el cuadro de prueba con la primera pregunta.
En el cuadro de la prueba, hay un encabezado con un título en el lado izquierdo y un cuadro de tiempo en el lado derecho. Este temporizador comenzará a disminuir de 15 a 0 segundos. Además consta de un indicador de línea de tiempo que se irá deslizando de izquierda a derecha según el temporizador. Si el usuario selecciona alguna de las opciones en esos 15 segundos, el temporizador se detendrá. Cuando esto ocurra todas las opciones disponibles se desactivarán, marcando la respuesta correcta.
Si la opción seleccionada por el usuario es correcta, el color de fondo cambia a verde. También va a mostrar el icono de marca para informar al usuario que la respuesta seleccionada es correcta. Si el usuario selecciona una opción que es incorrecta, el color de fondo cambia a rojo. Además se muestra el icono de cruz para informar al usuario que la opción seleccionada es incorrecta y la opción correcta se seleccionará automáticamente.
Si el usuario no selecciona una opción en los 15 segundos asignados a cada pregunta, el temporizador se detendrá una vez llegue a 0. Además la opción correcta de esa pregunta se seleccionará automáticamente.
Después de que aparezca la opción correcta en pantalla, el botón que dice «Siguiente» se activará y aparecerá en pantalla. Si hacemos clic sobre este, podremos pasar a la siguiente pregunta. En este ejemplo hay un total de cinco preguntas, pero se pueden añadir más de forma sencilla siguiendo la composición del archivo preguntas.js.
Cuando lleguemos al final del cuestionario, aparecerá el cuadro en el que se van a mostrar la puntuación obtenida por el usuario, además de dos botones como son, «Repetir» y «Salir«. Si hacemos clic en botón Repetir, la prueba volverá a comenzar con la pregunta número 1 y la puntuación a 0. En caso de hacer clic en el botón Salir del cuestionario, la ventana actual se volverá a cargar y el cuestionario comenzará desde el principio del todo.
¿Cómo crear un cuestionario con temporizador utilizando HTML, CSS y JavaScript?
Para crear esta aplicación web de cuestionario con temporizador, primero será necesario crear los archivos necesarios. Esto son un archivo HTML, un archivo CSS y los otros dos son archivos JavaScript. Después de crear estos archivos, tan solo tendrás que pegar los siguientes códigos dentro del correspondiente archivo.
HTML
El primero de los archivos que vamos a crear se llamará index.html, y dentro tan solo tendremos que pegar el siguiente código.
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Preguntas y respuestas </title> <link rel="stylesheet" href="style.css"/> <!-- FontAweome para los iconos--> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"/> </head> <body> <!-- Botón para empezar el cuestionario --> <div class="start_btn"><button>Empezar el cuestionario</button></div> <!-- Caja Info --> <div class="info_box"> <div class="info-title"><span>Las reglas básicas del cuestionario</span></div> <div class="info-list"> <div class="info">1. Tendrás <span>15 segundos</span> para responder a cada pregunta.</div> <div class="info">2. Una vez que selecciones una respuesta, <span>no se puede deshacer</span>.</div> <div class="info">3. No puede seleccionar ninguna opción una vez que se acaba el tiempo.</div> <div class="info">4. <span>No se puede salir de cuestionario</span> mientras se está desarrollando por que perderás todos los puntos acumulados.</div> <div class="info">5. Obtendrás <span>un punto por cada respuesta correcta</span>.</div> </div> <div class="buttons"> <button class="quit">Salir</button> <button class="restart">Continuar</button> </div> </div> <!-- Caja de preguntas --> <div class="quiz_box"> <header> <div class="title">Piénsalo antes de responder ...</div> <div class="timer"> <div class="time_left_txt">Tiempo restante</div> <div class="timer_sec">15</div> </div> <div class="time_line"></div> </header> <section> <div class="que_text"> <!-- Aquí he insertado una pregunta de JavaScript --> </div> <div class="option_list"> <!-- Aquí he insertado opciones de JavaScript --> </div> </section> <!-- pie de página de Quiz Box --> <footer> <div class="total_que"> <!-- Aquí he insertado Número de conteo de preguntas de JavaScript --> </div> <button class="next_btn">Siguiente</button> </footer> </div> <!-- Cuadro de resultados --> <div class="result_box"> <div class="icon"> <i class="fas fa-crown"></i> </div> <div class="complete_text">Has completado el cuestionario!</div> <div class="score_text"> <!-- Aquí he insertado Score Result de JavaScript --> </div> <div class="buttons"> <button class="restart">Repetir</button> <button class="quit">Salir</button> </div> </div> <!-- Dentro de este archivo JavaScript, solo he insertado preguntas y opciones. --> <script src="js/preguntas.js"></script> <!-- Dentro de este archivo JavaScript he codificado todos los códigos de prueba --> <script src="js/script.js"></script> </body> </html>
Archivos JavaScript
Archivo scripts.js
En primero de los dos archivos JavaScript necesarios, será el que vamos a usar para que la aplicación haga lo que tiene que hacer. Este archivo se va a llamar scripts.js y lo guardaremos dentro de una carpeta llamada js, como se indica en el archivo index.html.
//seleccionamos los recursos necesarios const start_btn = document.querySelector(".start_btn button"); const info_box = document.querySelector(".info_box"); const exit_btn = info_box.querySelector(".buttons .quit"); const continue_btn = info_box.querySelector(".buttons .restart"); const quiz_box = document.querySelector(".quiz_box"); const result_box = document.querySelector(".result_box"); const option_list = document.querySelector(".option_list"); const time_line = document.querySelector("header .time_line"); const timeText = document.querySelector(".timer .time_left_txt"); const timeCount = document.querySelector(".timer .timer_sec"); // Si hacemos clic en el botón empezar start_btn.onclick = ()=>{ info_box.classList.add("activeInfo"); //mostrar la caja info } // Si se pulsa el botón salir exit_btn.onclick = ()=>{ info_box.classList.remove("activeInfo"); // esconder la caja info } // Si se hace clic en el botón continuar continue_btn.onclick = ()=>{ info_box.classList.remove("activeInfo"); //esconder la caja info quiz_box.classList.add("activeQuiz"); //mostrar la caja de preguntas showQuetions(0); //llamar a la función showQestions para mostrar las preguntas queCounter(1); // pasamos el parámetro 1 a la función queCounter startTimer(15); //Llamamos a la función startTimer startTimerLine(0); //Llamamos a la función startTimerLine } // Establecermos valores let timeValue = 15; let que_count = 0; let que_numb = 1; let userScore = 0; let counter; let counterLine; let widthValue = 0; const restart_quiz = result_box.querySelector(".buttons .restart"); const quit_quiz = result_box.querySelector(".buttons .quit"); // Si pulsamos el botón Repetir cuestionario restart_quiz.onclick = ()=>{ quiz_box.classList.add("activeQuiz"); //Mostrar la caja de preguntas result_box.classList.remove("activeResult"); //esconder la caja de resultado timeValue = 15; que_count = 0; que_numb = 1; userScore = 0; widthValue = 0; showQuetions(que_count); //llamando a la función showQestions queCounter(que_numb); //pasando el valor que_numb a queCounter clearInterval(counter); //limpiar contador clearInterval(counterLine); //limpiar counterLine startTimer(timeValue); // llamar al a función startTimer startTimerLine(widthValue); //llamar a la función startTimerLine timeText.textContent = "Time Left"; //cambie el texto de timeText a Time Left next_btn.classList.remove("show"); //esconder el botón siguiente } // si se hace clic en el botón Salir quit_quiz.onclick = ()=>{ window.location.reload(); //recargar la ventana actual } const next_btn = document.querySelector("footer .next_btn"); const bottom_ques_counter = document.querySelector("footer .total_que"); // si se hace clic en el botón Next next_btn.onclick = ()=>{ if(que_count < questions.length - 1){ //si el número de preguntas es menor que la longitud total de la pregunta que_count++; //incrementar el valor que_count que_numb++; //ncrementar el valor que_numb showQuetions(que_count); //llamando a la función showQestions queCounter(que_numb); //pasando el valor que_numb a queCounter clearInterval(counter); //limpiar contador clearInterval(counterLine); //limpiar counterLine startTimer(timeValue); //llamando a la función startTimer startTimerLine(widthValue); //llamando a la función startTimerLine timeText.textContent = "Tiempo restante"; //cambiar el texto de tiempo a tiempo restante next_btn.classList.remove("show"); //ocultar el botón siguiente }else{ clearInterval(counter); //limpiar contador clearInterval(counterLine); //limpiar counterLine showResult(); //llamando a la función showResult } } // obtener preguntas y opciones del array function showQuetions(index){ const que_text = document.querySelector(".que_text"); //creando una nueva etiqueta span y div para la pregunta y la opción y pasando el valor usando el índice de array let que_tag = '<span>'+ questions[index].numb + ". " + questions[index].question +'</span>'; let option_tag = '<div class="option"><span>'+ questions[index].options[0] +'</span></div>' + '<div class="option"><span>'+ questions[index].options[1] +'</span></div>' + '<div class="option"><span>'+ questions[index].options[2] +'</span></div>' + '<div class="option"><span>'+ questions[index].options[3] +'</span></div>'; que_text.innerHTML = que_tag; //agregando una nueva etiqueta de intervalo dentro de que_tag option_list.innerHTML = option_tag; //agregando una nueva etiqueta div dentro de option_tag const option = option_list.querySelectorAll(".option"); // establecer el atributo onclick para todas las opciones disponibles for(i=0; i < option.length; i++){ option[i].setAttribute("onclick", "optionSelected(this)"); } } // creando las nuevas etiquetas div que para los iconos let crossIconTag = '<div class="icon cross"><i class="fas fa-times"></i></div>'; let tickIconTag = '<div class="icon tick"><i class="fas fa-check"></i></div>'; //Si la usuario hace clic en la opción function optionSelected(answer){ clearInterval(counter); //limpiar contador clearInterval(counterLine); //limpiar counterLine let userAns = answer.textContent; //obtener la opción seleccionada por el usuario let correcAns = questions[que_count].answer; //obtener la respuesta correcta de la matriz const allOptions = option_list.children.length; //obtener todos los artículos de opción if(userAns == correcAns){ //si la opción seleccionada por el usuario es igual a la respuesta correcta de la matriz userScore += 1; //mejora el valor de la puntuación con 1 answer.classList.add("correct"); //agregando color verde para corregir la opción seleccionada answer.insertAdjacentHTML("beforeend", tickIconTag); //agregando un ícono de marca para corregir la opción seleccionada console.log("Respuestas correctas"); console.log("Tus respuestas correctas = " + userScore); }else{ answer.classList.add("incorrect"); //agregando color rojo para corregir la opción seleccionada answer.insertAdjacentHTML("beforeend", crossIconTag); //agregando un icono de cruz para corregir la opción seleccionada console.log("Respuesta incorrecta"); for(i=0; i < allOptions; i++){ if(option_list.children[i].textContent == correcAns){ //si hay una opción que coincide con una respuesta de matriz option_list.children[i].setAttribute("class", "option correct"); //agregando color verde a la opción coincidente option_list.children[i].insertAdjacentHTML("beforeend", tickIconTag); //agregando el icono de marca a la opción coincidente console.log("Autoselección de la respuesta correcta."); } } } for(i=0; i < allOptions; i++){ option_list.children[i].classList.add("disabled"); //una vez que el usuario selecciona una opción, deshabilita todas las opciones } next_btn.classList.add("show"); //mostrar el siguiente botón si el usuario seleccionó alguna opción } function showResult(){ info_box.classList.remove("activeInfo"); //esconder la caja de info quiz_box.classList.remove("activeQuiz"); //esconder la caja de pregunta result_box.classList.add("activeResult"); //mostrar la caja del resultado const scoreText = result_box.querySelector(".score_text"); if (userScore > 4){ //Si el usuario acertó más de 3 respuestas //crear una nueva etiqueta de intervalo y pasar el número de puntuación del usuario y el número total de preguntas let scoreTag = '<span>Felicidades! 🎉, has acertado <p>'+ userScore +'</p> preguntas de <p>'+ questions.length +'</p></span>'; scoreText.innerHTML = scoreTag; //agregando una nueva etiqueta de intervalo dentro de score_Text } else if(userScore > 1){ // Si el usuario acertó más de 1 let scoreTag = '<span>Muy bien 😎, has acertado <p>'+ userScore +'</p> preguntas de <p>'+ questions.length +'</p></span>'; scoreText.innerHTML = scoreTag; } else{ // si el usuario acertó menos de 1 let scoreTag = '<span>Lo siento 😐, solo has acertado <p>'+ userScore +'</p> pregunta de <p>'+ questions.length +'</p></span>'; scoreText.innerHTML = scoreTag; } } function startTimer(time){ counter = setInterval(timer, 1000); function timer(){ timeCount.textContent = time; //Cambiamos el valor de timeCount con el valor de tiempo time--; //decrementamos el valor de tiempo if(time < 9){ //Si time es menor que 9 let addZero = timeCount.textContent; timeCount.textContent = "0" + addZero; //Añadimos 0 antes del valor tiempo } if(time < 0){ //Si tiempo es menor que 0 clearInterval(counter); //limpiamos el contador timeText.textContent = "TIEMPO!!"; //Cambiamos el texto de timpo const allOptions = option_list.children.length; //obtenemos todos los items de opciones let correcAns = questions[que_count].answer; //Obtenemos la respuesta correcta del array for(i=0; i < allOptions; i++){ if(option_list.children[i].textContent == correcAns){ //Si hay una opción que coincide con una respuesta del array option_list.children[i].setAttribute("class", "option correct"); //añadimos el color color verde a la opción seleccionada option_list.children[i].insertAdjacentHTML("beforeend", tickIconTag); //añadir el icono del tick a la selección console.log("Se acabó el tiempo: Autoselección de la respuesta correcta."); } } for(i=0; i < allOptions; i++){ option_list.children[i].classList.add("disabled"); //Cuando el usuario selecciona una opción, deshabilitamos las demás } next_btn.classList.add("show"); //Mostrar el botón siguiente, si el usuario seleccionó alguna opción } } } function startTimerLine(time){ counterLine = setInterval(timer, 29); function timer(){ time += 1; //actualizar el valor de timpo en 1 time_line.style.width = time + "px"; //incrementar el width de time_line con los px del valor de tiempo if(time > 549){ //Si el valor de time es mayor que 549 clearInterval(counterLine); //limpiar counterLine } } } function queCounter(index){ //creating a new span tag and passing the question number and total question let totalQueCounTag = '<span><p>'+ index +'</p> de <p>'+ questions.length +'</p> preguntas</span>'; bottom_ques_counter.innerHTML = totalQueCounTag; //adding new span tag inside bottom_ques_counter }
Archivo preguntas.js
El segundo archivo JS, el cual también vamos a guardar dentro de la carpeta js, será el que utilizaremos para almacenar las preguntas que haremos a los usuarios. Este archivo lo vamos a llamar preguntas.js. Si quieres añadir más preguntas, tan solo tendrás que utilizar el mismo esquema para cada pregunta como las que se muestran en este ejemplo.
// creando una matriz y pasando el número, preguntas, opciones y respuestas let questions = [ { numb: 1, question: "¿En qué equipo corre Carlos Sainz Jr.?", answer: "Ferrari", options: [ "Mercedes", "Ferrari", "Redbull", "Citroën" ] }, { numb: 2, question: "¿Cuanto tiempo tarda el sol en dar una vuelta a la tierra?", answer: "0 días", options: [ "0 días", "80 días", "364 días", "365 días" ] }, { numb: 3, question: "¿Cuantas posibilidades hay de ganar el euromillón?", answer: "1 entre 139.838.160 posibilidades", options: [ "10 entre 100.003.061 posibilidades", "5 entre 160 posibilidades", "1101 entre 10.838.111 posibilidades", "1 entre 139.838.160 posibilidades" ] }, { numb: 4, question: "¿Qué se puede programar con HTML?", answer: "Nada, HTML es un lenguaje para estructurar una web", options: [ "Bucles anidados", "Nada, HTML es un lenguaje para estructurar una web", "Estadística y PDO", "Es un lenguaje para programar threads" ] }, { numb: 5, question: "¿Qué Felipe reina en España?", answer: "Felipe UVE Palito", options: [ "El Rey de España se llama Froilan", "Felipe Palito Palito Palito", "Felipe UVE Palito", "¿Felipe? España es una república" ] }, ];
Archivo style.css
Para darle cierto estilo al cuestionario y a lo que vamos a ver en pantalla, vamos a crear un archivo llamado style.css. Dentro solo tendremos que guardar el siguiente código.
*{ margin: 0; padding: 0; box-sizing: border-box; font-family: 'Arial', sans-serif; } body{ background: #360077;; } ::selection{ color: #fff; background: #ae00ff9c; } .start_btn, .info_box, .quiz_box, .result_box{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } .info_box.activeInfo, .quiz_box.activeQuiz, .result_box.activeResult{ opacity: 1; z-index: 5; pointer-events: auto; transform: translate(-50%, -50%) scale(1); } .start_btn button{ font-size: 30px; font-weight: bold; color: #ffffff; padding: 15px 30px; outline: none; border: none; border-radius: 5px; background: rgb(86, 21, 102); cursor: pointer; } .start_btn button:hover{ color:#007bff } .info_box{ width: 540px; background: #fff; border-radius: 5px; transform: translate(-50%, -50%) scale(0.9); opacity: 0; pointer-events: none; transition: all 0.3s ease; } .info_box .info-title{ height: 60px; width: 100%; border-bottom: 1px solid lightgrey; display: flex; align-items: center; padding: 0 30px; border-radius: 5px 5px 0 0; font-size: 20px; font-weight: 600; } .info_box .info-list{ padding: 15px 30px; } .info_box .info-list .info{ margin: 5px 0; font-size: 17px; } .info_box .info-list .info span{ font-weight: 600; color: #007bff; } .info_box .buttons{ height: 60px; display: flex; align-items: center; justify-content: flex-end; padding: 0 30px; border-top: 1px solid lightgrey; } .info_box .buttons button{ margin: 0 5px; height: 40px; width: 100px; font-size: 16px; font-weight: 500; cursor: pointer; border: none; outline: none; border-radius: 5px; border: 1px solid #007bff; transition: all 0.3s ease; } .quiz_box{ width: 550px; background: #fff; border-radius: 5px; transform: translate(-50%, -50%) scale(0.9); opacity: 0; pointer-events: none; transition: all 0.3s ease; } .quiz_box header{ position: relative; z-index: 2; height: 70px; padding: 0 30px; background: #fff; border-radius: 5px 5px 0 0; display: flex; align-items: center; justify-content: space-between; box-shadow: 0px 3px 5px 1px rgba(0,0,0,0.1); } .quiz_box header .title{ font-size: 20px; font-weight: 600; } .quiz_box header .timer{ color: #ffffff; background: #7700ff; border: 1px solid #2a0046; height: 45px; padding: 0 8px; border-radius: 5px; display: flex; align-items: center; width: 150px; } .quiz_box header .timer .time_left_txt{ font-weight: 400; font-size: 18px; user-select: none; } .quiz_box header .timer .timer_sec{ font-size: 18px; font-weight: 400; height: 30px; width: 50px; color: #fff; border-radius: 5px; line-height: 30px; text-align: center; background: #343a40; border: 1px solid #343a40; user-select: none; margin-left: 4px; } .quiz_box header .time_line{ position: absolute; bottom: 0px; left: 0px; height: 3px; background: #007bff; } section{ padding: 25px 30px 20px 30px; background: #fff; } section .que_text{ font-size: 25px; font-weight: 600; } section .option_list{ padding: 20px 0px; display: block; } section .option_list .option{ background: aliceblue; border: 1px solid #84c5fe; border-radius: 5px; padding: 8px 15px; font-size: 17px; margin-bottom: 15px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; justify-content: space-between; } section .option_list .option:last-child{ margin-bottom: 0px; } section .option_list .option:hover{ color: #004085; background: #e4ccff; border: 1px solid #7100f1; } section .option_list .option.correct{ color: #155724; background: #d4edda; border: 1px solid #c3e6cb; } section .option_list .option.incorrect{ color: #721c24; background: #f8d7da; border: 1px solid #f5c6cb; } section .option_list .option.disabled{ pointer-events: none; } section .option_list .option .icon{ height: 26px; width: 26px; border: 2px solid transparent; border-radius: 50%; text-align: center; font-size: 13px; pointer-events: none; transition: all 0.3s ease; line-height: 24px; } .option_list .option .icon.tick{ color: #23903c; border-color: #23903c; background: #d4edda; } .option_list .option .icon.cross{ color: #a42834; background: #f8d7da; border-color: #a42834; } footer{ height: 60px; padding: 0 30px; display: flex; align-items: center; justify-content: space-between; border-top: 1px solid lightgrey; } footer .total_que span{ display: flex; user-select: none; } footer .total_que span p{ font-weight: 500; padding: 0 5px; } footer .total_que span p:first-child{ padding-left: 0px; } footer button{ height: 40px; padding: 0 13px; font-size: 18px; font-weight: 400; cursor: pointer; border: none; outline: none; color: #fff; border-radius: 5px; background: #007bff; border: 1px solid #007bff; line-height: 10px; opacity: 0; pointer-events: none; transform: scale(0.95); transition: all 0.3s ease; } footer button:hover{ background: #0263ca; } footer button.show{ opacity: 1; pointer-events: auto; transform: scale(1); } .result_box{ background: #fff; border-radius: 5px; display: flex; padding: 25px 30px; width: 450px; align-items: center; flex-direction: column; justify-content: center; transform: translate(-50%, -50%) scale(0.9); opacity: 0; pointer-events: none; transition: all 0.3s ease; } .result_box .icon{ font-size: 125px; color: #50006c; margin-bottom: 10px; } .result_box .complete_text{ font-size: 20px; font-weight: 500; } .result_box .score_text span{ display: flex; margin: 10px 0; font-size: 18px; font-weight: 500; } .result_box .score_text span p{ padding: 0 4px; font-weight: 600; } .result_box .buttons{ display: flex; margin: 20px 0; } .result_box .buttons button{ margin: 0 10px; height: 45px; padding: 0 20px; font-size: 18px; font-weight: 500; cursor: pointer; border: none; outline: none; border-radius: 5px; border: 1px solid #007bff; transition: all 0.3s ease; } .buttons button.restart{ color: #fff; background: #6200ff; } .buttons button.restart:hover{ background: #4f018fb0; } .buttons button.quit{ color: #6200ff; background: #fff; } .buttons button.quit:hover{ color: #fff; background: #4f018fb0; }
Si quieres ver funcionando este pequeño proyecto, puedes verlo en el siguiente link. Hay que decir que a este cuestionario le faltan algunas cosas. Por ejemplo mezclar las respuestas y las preguntas cada vez que se ejecuta la aplicación, ya que siempre aparecerá en el mismo orden. Pero esto supongo que si a alguien le interesa podrá hacerlo metiendo mano al archivo scripts.js.