Cómo crear una aplicación TODO con Vanilla JavaScript (y almacenamiento local)

1. Comience con los activos requeridos

Para hacer que el diseño sea un poco más exclusivo, usaremos algunas ilustraciones SVG hechas a mano y una fuente personalizada tomada de Elementos de Envato.

Vale la pena señalar que la mayoría de estos activos provendrán de un tutorial anterior. De hecho, también usaremos muchas de las técnicas de posicionamiento que aprendimos en este tutorial, así que vale la pena leerlo.

Cómo construir un formulario SVG hecho a mano receptivo

2. Continuar con el marcado de página

Comenzaremos con un SVG y un div envase:

sprites SVG

Como lo hemos hecho muchas veces en el pasado, como buena práctica, almacenaremos todos los SVG como symbols en un contenedor de sprites SVG. Luego, los representaremos en la pantalla siempre que lo necesitemos llamando al use elemento.

Aquí está el marcado para el sprite SVG:

Observe la preserveAspectRatio="none" atributo que adjuntamos a la mayoría de las ilustraciones. Hicimos esto porque, como veremos más adelante, nuestros íconos escalarán y perderán sus dimensiones iniciales.

Envase

El contenedor incluirá un formulario, un div y una lista ordenada vacía:

Dentro del formulario, tendremos una entrada y un botón de envío junto con sus SVG asociados:

Observe la name atributo que hemos agregado al campo de entrada. Más adelante usaremos este atributo para acceder al valor de entrada después del envío del formulario.

Nota: En nuestra demostración, el autofocus El atributo del campo de texto no funcionará. De hecho, arrojará el siguiente error que puede ver si abre la consola de su navegador:

El error de origen cruzado debido al atributo de enfoque automático

Sin embargo, si ejecuta esta aplicación localmente (no como un proyecto de Codepen), este problema no existirá. Alternativamente, puede establecer el enfoque a través de JavaScript.

Dentro de divcolocaremos tres anidados divs y el SVG asociado. En esta sección, realizaremos un seguimiento del número total de tareas (tanto restantes como completadas):

Finalmente, los elementos de la lista ordenada se agregarán dinámicamente a través de JavaScript.

3. Definir algunos estilos básicos

Con el marcado listo, continuaremos con algunos estilos de reinicio:

4. Establecer los estilos principales

Analicemos ahora los principales estilos de nuestra aplicación TODO.

Estilos de contenedores

El contenedor tendrá un ancho máximo con contenido centrado horizontalmente:

Estilos de formulario

En pantallas pequeñas, todos los elementos del formulario se apilarán:

El diseño del formulario en pantallas pequeñas

Sin embargo, en las ventanas gráficas de 600 píxeles de ancho o más, el diseño del formulario cambiará de la siguiente manera:

El diseño del formulario en pantallas medianas y superiores

Tomemos nota de dos cosas:

  • En ventanas anchas, la entrada será el doble del tamaño del botón.
  • Los SVG serán elementos absolutamente posicionados y se ubicarán debajo de su control de formulario adyacente. Nuevamente, para una explicación más detallada, echa un vistazo a este tutorial anterior.

Aquí están los estilos para esta sección:

Estilos de estadísticas

A continuación, echemos un vistazo a la barra de estado que nos dará un informe rápido sobre el número total de tareas.

En pantallas pequeñas tendrá la siguiente apariencia apilada:

El diseño de estadísticas en pantallas pequeñas.

Sin embargo, en ventanas gráficas de 600 píxeles de ancho o más, debería cambiar de la siguiente manera:

El diseño de estadísticas en pantallas medianas y superiores

Tomemos nota de dos cosas:

  • En ventanas anchas, todos los niños div los elementos tendrán el mismo ancho.
  • De manera similar a los SVG anteriores, este también estará absolutamente posicionado y actuará como una imagen de fondo que cubre toda la sección.

Los estilos relacionados:

Estilos de tareas

El diseño de tareas, que generaremos dinámicamente en la próxima sección, se verá así:

El diseño de tareas

Cada tarea que estará representada por un li tendrá dos partes.

La representación de marcado de una tarea

En la primera parte, verá una casilla de verificación junto con el nombre de la tarea. En la segunda parte, notará un botón de eliminación para eliminar la tarea.

Estos son los estilos relacionados:

Cuando una tarea es incompleto, aparecerá una casilla de verificación vacía. Por otro lado, si una tarea está marcada como terminado, aparecerá una marca de verificación. Además, su nombre tendrá un 50 % de opacidad y una línea que lo atravesará.

Estos son los estilos responsables de este comportamiento:

Finalmente, a continuación se muestran los estilos para el botón Eliminar:

5. Agregar el JavaScript

En este punto, estamos listos para construir la funcionalidad central de nuestra aplicación de lista TODO. ¡Vamos a hacerlo!

Sobre el envío del formulario

Cada vez que un usuario envía el formulario pulsando el botón Ingresar llave o la Enviar botón, haremos lo siguiente:

  1. Detenga el envío del formulario, evitando así que se vuelva a cargar la página.
  2. Tome el valor que está contenido en el campo de entrada.
  3. Suponiendo que el campo de entrada no esté vacío, crearemos un nuevo objeto literal que representará la tarea. Cada tarea tendrá una identificación única, un nombre y estará activa (no completada) de forma predeterminada.
  4. Agregue esta tarea a la tasks formación.
  5. Guarde la matriz en el almacenamiento local. El almacenamiento local solo admite cadenas, por lo que para hacerlo, debemos usar el JSON.stringify() método para convertir los objetos dentro de la matriz en cadenas.
  6. Llama a createTask() función para representar visualmente la tarea en la pantalla.
  7. Borrar el formulario.
  8. Enfoca el campo de entrada.

Aquí está el código relevante:

Crear una tarea

los createTask() La función será responsable de crear el marcado de la tarea.

Por ejemplo, aquí está la estructura para la tarea «Ir a caminar»:

La estructura de marcado para una tarea

Dos cosas son importantes aquí:

  • Si se completa la tarea, aparecerá la marca de verificación.
  • Si la tarea no se completa, es span elemento recibirá el contenteditable atributo. Este atributo nos dará la posibilidad de editar/actualizar su nombre.

A continuación se muestra la sintaxis de esta función:

Actualizar una tarea

Una tarea se puede actualizar de dos maneras diferentes:

  • Cambiando su estado de “incompleto” a “completado” y viceversa.
  • Modificando su nombre en caso de que la tarea esté incompleta. Recuerde que en este caso, el span elemento tiene el contenteditable atributo.

Para realizar un seguimiento de estos cambios, aprovecharemos la input evento. Este es un evento aceptable para nosotros porque se aplica tanto a input elementos y elementos con contenteditable activado.

Lo complicado es que no podemos adjuntar directamente este evento a los elementos de destino (casilla de verificación, span) porque se crean dinámicamente y no forman parte del DOM en la carga de la página.

Gracias a delegación de eventosadjuntaremos el input event a la lista principal que forma parte del marcado inicial. Entonces, a través de la target propiedad de ese evento, verificaremos los elementos en los que ocurrió el evento y llamaremos al updateTask() función:

Dentro de updateTask() función, haremos lo siguiente:

  1. Tome la tarea que necesita ser actualizada.
  2. Compruebe el elemento que desencadenó el evento. Si el elemento tiene la contenteditable atributo (es decir, es el span elemento), estableceremos el nombre de la tarea igual al spanel contenido del texto.
  3. De lo contrario (es decir, es la casilla de verificación), alternaremos el estado de la tarea y su checked atributo. Además, también alternaremos el contenteditable atributo del adyacente span.
  4. Actualizar el valor de la tasks clave en el almacenamiento local.
  5. Llama a countTasks() función.

Aquí está la sintaxis para esta función:

Quitar una tarea

Podemos eliminar una tarea a través del botón “cerrar”.

Botón para eliminar una tarea

Similar a la operación de actualización, no podemos adjuntar directamente un evento a este botón porque no está en el DOM cuando se carga la página.

Gracias de nuevo a la delegación del evento, adjuntaremos un click evento a la lista principal y realizar las siguientes acciones:

  1. Compruebe si el elemento en el que se hace clic es el botón «cerrar» o su SVG secundario.
  2. Si eso sucede, tomaremos el id del elemento de la lista principal.
  3. pasa esto id hacia removeTask() función.

Aquí está el código relevante:

Dentro de removeTask() función, haremos las siguientes cosas:

  1. Quitar de la tasks array la tarea asociada.
  2. Actualizar el valor de la tasks clave en el almacenamiento local.
  3. Eliminar el elemento de lista asociado.
  4. Llama a countTasks() función.

Aquí está la sintaxis para esta función:

Contar tareas

Como ya hemos discutido, muchas de las funciones anteriores incluyen el countTask() función.

Su trabajo es monitorear las tareas en busca de cambios (adiciones, actualizaciones, eliminaciones) y actualizar el contenido de los elementos relacionados.

Contar tareas

Aquí está su firma:

Impedir la adición de nuevas líneas

Cada vez que un usuario actualice el nombre de una tarea, no debería poder crear nuevas líneas presionando el botón Ingresar llave.

Prevenir líneas múltiples

Para deshabilitar esta funcionalidad, una vez más aprovecharemos la delegación de eventos y adjuntaremos el keydown evento a la lista, así:

Tenga en cuenta que en este escenario sólo el span elementos podrían desencadenar ese evento, por lo que no es necesario realizar una verificación adicional como esta:

Conservar datos en la carga de la página

Hasta ahora, si cerramos el navegador y navegamos hasta el proyecto de demostración, nuestras tareas desaparecerán.

Pero, espera, ¡eso no es 100% cierto! Recuerde que cada vez que hacemos una manipulación de tareas, también almacenamos el tasks matriz en el almacenamiento local. por ejemplo, en Cromopara ver las claves y los valores de almacenamiento local, haga clic en el Solicitud luego, expanda la Almacenamiento local y finalmente haga clic en un dominio para ver sus pares clave-valor.

En mi caso, aquí están los valores para el tasks llave:

Un ejemplo con almacenamiento local

Entonces, para mostrar estas tareas, primero debemos recuperarlas del almacenamiento local. Para hacer esto, usaremos el JSON.parse() método que convertirá las cadenas de nuevo en objetos JavaScript.

A continuación, almacenaremos todas las tareas en el familiar tasks formación. Tenga en cuenta que si no hay datos en el almacenamiento local (por ejemplo, la primera vez que visitamos la aplicación), esta matriz está vacía. Luego, tenemos que iterar a través de la matriz y, para cada tarea, llamar a la createTask() función. ¡Y eso es todo!

El fragmento de código correspondiente:

Conclusión

¡Uf! Gracias por acompañarnos en este largo viaje amigos. Con suerte, hoy adquirió nuevos conocimientos que podrá aplicar a sus propios proyectos.

Recordemos lo que construimos:

Sin duda, crear una aplicación de este tipo con un marco de JavaScript podría ser más estable, fácil y eficiente (repintar el DOM es costoso). Sin embargo, saber cómo resolver este tipo de ejercicio con JavaScript simple lo ayudará a obtener una comprensión sólida de sus fundamentos y lo convertirá en un mejor desarrollador de JavaScript.

Antes de cerrar, permítanme proponer dos ideas para extender este ejercicio:

  • Utilizar el API de arrastrar y soltar HTML o una biblioteca JavaScript como Ordenable.js para reordenar las tareas.
  • Almacene datos (tareas) en la nube en lugar del navegador. Por ejemplo, reemplace el almacenamiento local con una base de datos en tiempo real como base de fuego.

Como siempre, ¡muchas gracias por leer!

Más aplicaciones JavaScript Vanilla

Si desea aprender a crear aplicaciones pequeñas con JavaScript simple, consulte los siguientes tutoriales:

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *