logoCoderhouse.png
By Nicolas Alliaume • agosto 29, 2018

Desarrolla tu propia Trivia Web | Tutorial de JS y jQuery

¡Hola! Soy Nico Alliaume, profesor de Coderhouse y en este tutorial les contaré paso a paso de cómo podemos crear nuestra propia trivia web. Me enfocaré principalmente en la parte de Javascript y el uso de jQuery.

El juego

El juego consiste en una serie de preguntas con cuatro opciones, de las cuales sólo una es válida. El jugador tendrá un tiempo límite para responder cada una. Si el tiempo se acaba, el juego termina. Si el jugador acierta, sumará 10 puntos.
Al contestar todas las preguntas o quedarse sin tiempo, se muestra en pantalla los puntos obtenidos.

Suena fácil, ¿no?
 

El HTML

El HTML de nuestro trivia se ve bastante sencillo.

No te asustes si mirás este HTML con un navegador ahora mismo, ¡es horrible! Pero es porque aún no hemos hecho la magia del CSS.

Le voy a dar imaginariamente 10 puntos extra al que se dijo: ¿dónde están las preguntas? ¡Ya llegaremos a eso! Las preguntas las incluiremos más adelante desde Javascript, por ahora seguime con el CSS.

El CSS

He aquí el CSS del trivia.

 

¡Bueno, de CSS sí hay bastante código! Pero verás que es sencillo.

Me detendré solamente en uno de los selectores (soy fanático de los selectores ¿viste mi post anterior? Podés verlo acá):

.card.question .options > li input:checked + label

Antes de explicar qué es este selector quisiera aclarar algo. Como comenté al comienzo, el juego muestra preguntas con cuatro opciones de respuesta, de las cuales sólo una es correcta.

La forma en la que he maquetado el HTML para las opciones de respuesta es la siguiente: un checkbox, con un label asociado de la siguiente forma:

<input type='radio' name='question[0]' value='0' id='q0o1'>

<label for='q0o1'>Opción 1</label>

Dicho esto, volvemos al selector:

.card.question .options > li input:checked + label

Este selector selecciona los elementos de tipo label que son hermanos de elementos de tipo input que estén checkeados (marcados con el tick), que a su vez son descendientes de elementos de tipo li, que sean hijos directos de elementos de clase options, descendientes de elementos de clase card y question simultáneamente. ¡Wow! Eso fue un poco mucho. Veámoslo gráficamente:

Label

 

El selector recorre todo el camino desde los elementos con clase card y question hasta llegar a la label hermana de un input en estado checked. Usaremos este selector para marcar la opción elegida por el usuario.

Ahora sí, vayamos al centro de la cuestión.

El Javascript

Desde Javascript ocurrirán muchas cosas: mantendremos el estado del juego (temporizador, puntaje, en qué pregunta estamos, etc.), crearemos las preguntas, mostraremos los distintos mensajes (comienzo, final), y controlaremos la lógica del juego (aumentar los puntos, actualizar la pantalla y más).

Veamos el código. Agregué comentarios con números que luego explicaré abajo uno a uno.

En este código Javascript utilizamos 2 bibliotecas: jQuery y Underscore.

____________________________________________________________________________________________________________________________

Curso de programación

________________________________________________________________________________________

Ahora me detendré especialmente en las funcionalidades relacionadas a jQuery.

Comencemos a ver punto por punto.

//1

 Al comienzo del script, inicializamos un array de arrays con la preguntas del juego. Cada elemento de este array corresponde a una pregunta, con el siguiente formato: el primer elemento (índice 0) es el texto de la pregunta, de segundo al quinto (índices 1 al 4) son las opciones de respuesta, y el último (índice 5) es la respuesta correcta (indicada de 0 a 3).

//2

Aquí utilizamos Underscore para generar un template de pregunta. Básicamente, un template de Underscore es un string que define la estructura de una cadena que generaremos más adelante, con la ventaja de poder incluir porciones dinámicas utilizando parámetros. Un ejemplo sencillo:

var t = _.template("Mi nombre es <%= name %>")

En este caso, la variable t es un template, que recibe el parámetro name. Cuando utilizamos el template y le indicamos el valor de name (por ejemplo: {name: Nico}), obtendremos una cadena que dice Mi nombre es Nico.

Utilizamos esta funcionalidad de templates de Underscore para generar el HTML de cada pregunta. Lo veremos más adelante.

//3

Definimos las variables de estado del juego y los valores iniciales (como el tiempo de respuesta de cada pregunta).

//4

Cuando utilizamos jQuery para manipular nuestra página, debemos asegurarnos que los elementos que vamos a manipular ya se encuentran en la página. Esto es muy importante, ya que usualmente puede cargarse nuestro código JS antes que varios elementos y si intentamos manipularlos obtendremos nada más que errores.

Para evitar esto, jQuery define una forma de asegurarnos que cierto código se ejecutará una vez que los elementos del DOM estén cargados.

Cuando escribimos $(function(){...}) le estamos diciendo a jQuery que llame a la función que le pasamos por parámetro cuando el DOM se haya cargado, y podemos manipular sus elementos tranquilamente. Escribirlo de la forma $(miFuncion) también es válido. En ese caso, jQuery llamará a la función miFuncion cuando el DOM esté listo. Y también puedes ver esto de la forma $(document).ready(function(){...});

//5

Utilizamos jQuery para escuchar el evento click del botón de Comenzar y Volver a jugar. El primero es el botón que comienza el juego. El segundo es un botón que mostramos al finalizar el juego para volver a jugar.

Cuando el jugador haga click en Comenzar, ejecutaremos la función start, y cuando haga click en Volver a jugar, llamaremos a restart.

//6

La función restart inicializa los valores de las variables de estado del juego.

//7

Aquí se oculta la pantalla de finalizar y un mensaje que dice Se acabó el tiempo, y se muestra la pantalla de comienzo. Finalmente, se generan las tarjetas con las preguntas y sus opciones, y se actualiza en pantalla el tiempo restante y el puntaje.

//8

La función start se ejecuta cuando el jugador hace click en comenzar. Quita el mensaje de comienzo y muestra la primer pregunta.

//9

Esta es una de las funciones clave del juego, encargada de generar las preguntas. Lo primero que hacemos es borrar las preguntas que puedan existir en el DOM (si estamos jugando por segunda vez), utilizando la función de jQuery .html(). Con esta función le decimos a jQuery qué queremos incluir en el DOM para determinados elementos (seleccionados por el selector). En este caso, queremos el string vacío en los elementos con clase questions. Si volvés al código HTML, verás que el div con la clase questions es un div vacío, que utilizaremos para contener a todas las preguntas.

En esta función usamos el template que generamos en //2 para crear el HTML de cada una de las preguntas. Con un for recorremos el array definido en //1 con las preguntas, y para cada un de ellas llamamos al template para obtener el HTML correspondiente. Este HTML lo agregamos al DOM utilizando .append(). Ésta función agrega elementos al final del contenido ya existente para los elementos seleccionados por el selector.

//10

Le indicamos a jQuery que nos interesa el evento change de los inputs dentro de los elementos con clase question y card (cada una de las preguntas). Con esto, cuando el jugador escoja una opción de respuesta, se ejecutará la función optionSelected() que verémos más adelante.

//11

Esta función cambia el estado del juego para pasar de una pregunta a la siguiente, y actualiza la página. Utilizamos la función .hide() para ocultar un elemento del DOM (la pregunta actual).

//12

Aquí mostramos la siguiente pregunta, e iniciamos el temporizador para contestar la nueva pregunta.

//13

Esta función inicializa el temporizador para responder una pregunta. Cuando nos movemos de pregunta, anulamos el temporizador anterior y lo volvemos a iniciar desde el tiempo inicial (en este caso son 8 segundos por pregunta). Cada 1 segundo, nuestro temporizador llamará a la función countdownTick() (//14).

//15

Mostramos la tarjeta de pregunta correspondiente al índice que la función recibe por parámetro. Para eso utilizamos la función de jQuery .show().

Me detendré un momento en el selector que utiliza esta función.

$('.question.card:nth-child(' + index + ')')

El objetivo es seleccionar el div de clase question y card que corresponde a la pregunta número index. Para esto utilizamos :nth-child(X), que selecciona el elemento del DOM que está en la posición X a partir del padre. Veámoslo con un ejemplo:

<div class="dad">

<span>1</span>

<span>2</span>

<span>3</span>

</div>

Dado este HTML, con el selector:

.dad span:nth-child(1): obtenemos el span que dice 1

.dad span:nth-child(2): obtenemos el span que dice 2

.dad span:nth-child(3): obtenemos el span que dice 3

Volviendo al juego, utilizamos nth-child para obtener la tarjeta de la pregunta que queremos mostrar en pantalla.

//16

La función countdownTick() se ejecuta cada un segundo, y actualiza el tiempo restante para responder en la pantalla del jugador. Si el tiempo restante es 0, entonces el juego termina.

//17

Actualiza el tiempo restante en pantalla, utilizando la función html() que hemos visto antes.

//18

Actualiza los puntos en pantalla, similar a //17.

//19

Esta es otra de las funciones claves del juego. Se ejecuta cuando el jugador escoge una respuesta. Lo primero que hacemos es castear el valor del input que seleccionó a valor entero utilizando parseInt(). Esto es porque el HTML guarda los valores como strings, y en nuestro array de preguntas (//1), el valor de la opción correcta es un entero.

Luego, verificamos si la opción elegida por el usuario es la correcta. De ser así, aumentamos los puntos y lo mostramos en pantalla. Además, hacemos una pequeña animación de "respuesta correcta", o de "respuesta incorrecta" si no acertó. Veremos estas animaciones en breve.

Finalmente, si no hay más preguntas, el juego termina. Si las hay, nos movemos a la siguiente.

//20 y //21

Animación de respuesta correcta e incorrecta. Simplemente llaman a animatePoints() con el parámetro adecuado. Lo vemos a continuación.

//22

Esta función anima el puntaje en pantalla. La animación está hecha con CSS utilizando transition, que simplemente crea una transición (de colores en este caso) en el texto del puntaje. Dependiendo del parámetro que recibe esta función es el color de la transición. Esto se hace utilizando dos clases: right y wrong. Podés volver sobre el CSS para ver qué tienen estas clases.

La animación hace una transición a otro color, y luego vuelve al original. Esto lo hacemos con un timer, que agrega y quita la clase "animada" medio segundo después de agregarla.

//23

Cuando el juego termina, esta función es ejecutada. Si el tiempo restante para responder preguntas es 0, quiere decir que el usuario perdió por tiempo, y mostramos un mensaje de "Se acabó el tiempo!".

Por último, ocultamos las preguntas y mostramos una tarjeta con los puntos finales y un botón para volver a jugar.

//24

Cuando la página termina de cargarse, luego de definir todas las funciones del juego, llamaremos a restart() para que el juego quede en estado de listo para jugar.

¡Wow! ¡Eso ha sido bastante por esta vez!

¿Cansado de leer? ¡Ahora a jugar!

Descargá el código completo del juego desde nuestra cuenta de GitHub aquí.

¿Te animás a agregar nuevas preguntas y a que se muestren en distinto orden cada vez que jugás?

¡Mucha suerte!