Entendiendo el DOM

1

Manipulación del DOM con JavaScript y APIs

2

Entendiendo el DOM y su Manipulación con JavaScript

3

Diferencias entre el DOM y el objeto Window en JavaScript

Seleccionando y Accesando a Elementos del DOM

4

Selección de Elementos del DOM con JavaScript

5

Navegación Jerárquica del DOM en JavaScript

Manipulando Elementos del DOM

6

Atributos y Propiedades en HTML y su Manipulación con JavaScript

7

Modificar texto en HTML con JavaScript

8

Modificar Estilos CSS con JavaScript: Propiedad Style y ClassName

9

Uso de classList para Manipular Clases en Elementos HTML

10

Manipulación del DOM con innerHTML e InsertAdjacentHTML

11

Agregar elementos HTML sin reemplazar contenido existente

12

Creación y Manipulación de Elementos DOM con createElement

13

Eliminar Elementos del DOM con JavaScript: Métodos y Ejemplos

14

Clonación y Reemplazo de Elementos en JavaScript

Manipulando Eventos en el DOM

15

Eventos y Flujo en Programación Web: Capturing y Bubbling

16

Manejo de Eventos en JavaScript: click, mouseOver y mouseOut

17

Manipulación de Eventos en JavaScript para Interacción de Elementos

18

Validación de Formularios con JavaScript: Prevenir Comportamiento por Defecto

19

Delegation Pattern en JavaScript: Mejora de Eventos Click en Listas

Creando un Administrador de Tareas

20

Creación de un Task Manager con Persistencia usando Local Storage

21

Interactividad en Botones de Tareas: Borrar y Editar en JavaScript

22

Persistencia de Datos con Local Storage en Tareas Web

23

Guardado y edición de tareas en local storage con JavaScript

24

Manejo de Errores en Local Storage para Tareas Dinámicas

25

Cambio de Tema Dinámico y Persistente en Aplicaciones Web

26

Creación de Páginas Web Dinámicas con JavaScript

Asincronía en JavaScript

27

Programación Síncrona y Asíncrona en JavaScript

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Cambio de Tema Dinámico y Persistente en Aplicaciones Web

25/27
Recursos

¿Cómo podemos implementar un botón para cambiar el tema de una aplicación?

A menudo queremos ofrecer a los usuarios la opción de personalizar la apariencia de nuestra aplicación web. Una de las funcionalidades favoritas es la de cambiar el tema entre claro (light) y oscuro (dark). Este tutorial te llevará por el proceso de implementación de un botón de alternancia de tema que recuerda la elección del usuario incluso al actualizar la página.

Preparación del entorno

Para empezar, necesitamos seleccionar el botón encargado de alternar el tema. Usaremos el método getElementById en document para obtener una referencia al botón de alternancia por su ID. Una vez tenemos la referencia, debemos agregar un evento que se dispare al hacer clic. Para ello, utilizamos addEventListener:

const tempToggleButton = document.getElementById('toggleButton');

tempToggleButton.addEventListener('click', () => {
    document.body.classList.toggle('darkTheme');
});

Este sencillo fragmento de código permitirá que, al hacer clic en el botón, se agregue o quite la clase darkTheme del elemento body. De este modo, podremos ver el cambio visual en los estilos definidos para la clase darkTheme.

Implementación de la persistencia del tema

El siguiente paso es asegurarnos de que la preferencia del usuario se mantenga incluso después de recargar la página, algo vital para mejorar la experiencia del usuario. Para lograr la persistencia del tema, utilizaremos localStorage. Primero, validamos si el body contiene la clase darkTheme y almacenamos el resultado:

const theme = document.body.classList.contains('darkTheme') ? 'dark' : 'light';
localStorage.setItem('theme', theme);

Verificación del tema al cargar la página

Una vez almacenada la elección del usuario en localStorage, es importante que cada vez que la página cargue, verifiquemos este almacenamiento y ajustemos el tema en consecuencia. Podemos lograrlo con la siguiente validación al inicio de nuestro script:

const currentTheme = localStorage.getItem('theme');
if (currentTheme === 'dark') {
    document.body.classList.add('darkTheme');
}

Con esta lógica, al recargar la página, el tema seleccionado se mantiene de acuerdo con el valor guardado en localStorage.

Probando y asegurando la funcionalidad

Para asegurarte de que todo funcione correctamente, realiza una última verificación asegurándote de alternar entre temas y de que esta selección resista los reinicios de sesión:

  1. Cambia al tema oscuro, verifica que localStorage contiene theme = dark.
  2. Actualiza la página y verifica que el tema oscuro persista.
  3. Haz clic para volver al tema claro, comprueba que localStorage ahora tenga theme = light.

Consejos adicionales

  • Revisa que todos los estilos CSS necesarios estén correctamente definidos para ambas clases de tema.
  • Asegúrate de que los cambios de tema no interfieran con otros estilos visuales.
  • Considera añadir animaciones suaves para mejorar la transición entre temas.

La implementación efectiva y la persistencia del tema mejoran la accesibilidad y personalización de tu aplicación. ¡Sigue aprendiendo y mejorando la experiencia de tus usuarios!

Aportes 7

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Para solucionar el problema de la persistencia yo he decidido crear una función loadTheme( ) que se llama antes de loadTasks( ). * Esta función comprueba si en localStorage existe un theme y si lo hay, lo añade a las clases de body. * La clase 'light-theme' muestra los estilos default igual que si no estuviera ya que ni siquiera está en la CSS. ```js const themeToggleButton = document.getElementById('toggle-theme-btn') loadTheme() loadTasks() function loadTheme() { const theme = localStorage.theme if(theme) { document.body.classList.add(theme) } } themeToggleButton.addEventListener('click', () => { document.body.classList.toggle('dark-theme') const theme = document.body.classList.contains('dark-theme') ? 'dark-theme' : 'light-theme' localStorage.setItem('theme', theme) }) ```
comparto mi proyecto. me gusto el curo aprendí bastante y todo en la semana de platzi free :D <https://stivensonmejia.github.io/CursoJavaScript-ManipulacionDOM/?> ![](https://static.platzi.com/media/user_upload/image-89c724a0-b240-4523-b92a-20b00aff9faa.jpg)
![](https://static.platzi.com/media/user_upload/Screenshot%202025-03-24%20135311-ad631ff3-54b4-4137-ad2b-3b8729939d39.jpg)he tenido este problema con mi theme color black alguien me podria dar una idea de como podria solucionarlo
Como practica podrian implementar un select que les ponga la prioridad de la tarea ejemplo (alta,media,baja...etc)
Compartoel resultado de mi projecto: ![](https://static.platzi.com/media/user_upload/image-8015af25-ec1b-47f9-ae1c-c062193cd400.jpg) html: ```js <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Project Task Manager</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" integrity="sha384-tViUnnbYAV00FLIhhi3v/dWt3Jxw4gZQcNoSCxCIFNJVCx7/D55/wXsrNIRANwdD" crossorigin="anonymous"> </head> <body class="d-flex justify-content-center align-items-center vh-100"> <main class="container border rounded shadow p-3" style="background-color: #DEE2E6;">

Task Manager

<form class="d-flex my-3"> <input type="text" name="task" class="form-control me-2" placeholder="Add a task" required> <button type="submit" class="btn btn-primary"></button> </form>
  • Task content
    <button class="btn p-0 border-0"></button> <button class="btn p-0 border-0"></button>
</main> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script> <script src="task-manager.js"></script> </body> </html> ```js: ```js const taskList = document.getElementById("task-list"); loadTasksInLocalStorange(); // Add event to new task form document.querySelector("form").addEventListener("submit", (event) => { event.preventDefault(); const newTaskText = event.target.elements["task"].value; createTask(newTaskText); // Reset input event.target.elements["task"].value = ""; storeTaskInLocalStorage(newTaskText); }); // Add events to buttons (edit and remove [task]) taskList.addEventListener("click", (event) => { const clickedTarget = event.target; const li = clickedTarget.closest("li"); if (clickedTarget.classList.contains("bi-pencil-square")) { editTask(li); updateTaskInLocalStore(); } else if (clickedTarget.classList.contains("bi-trash")) { deleteTask(li); removeTaskFromLocalStorange(li.firstChild.textContent); } }); function createTask(task) { const newTaskItem = document.createElement("li"); newTaskItem.className = "list-group-item d-flex"; newTaskItem.textContent = task; const buttonContainer = document.createElement("div"); buttonContainer.className = "ms-auto"; buttonContainer.append(createButton("pencil-square"), createButton("trash")); newTaskItem.insertAdjacentElement("beforeend", buttonContainer); document.getElementById("task-list").append(newTaskItem); } function createButton(icon) { const button = document.createElement("button"); button.className = "btn p-0 border-0 me-1"; const buttonIcon = document.createElement("i"); buttonIcon.className= "bi bi-" + icon; button.append(buttonIcon); return button; } function editTask(task) { const updateTask = prompt("Update the task:"); if (updateTask !== null) { task.firstChild.textContent = updateTask; } } function deleteTask(task) { if (confirm("Are you sure?")) { task.remove(); } } function loadTasksInLocalStorange() { const tasks = JSON.parse(localStorage.getItem("tasks") || "[]"); for (task of tasks) { createTask(task); } } function storeTaskInLocalStorage(task) { const tasks = JSON.parse(localStorage.getItem("tasks") || "[]"); tasks.push(task); localStorage.setItem("tasks", JSON.stringify(tasks)); } function updateTaskInLocalStore() { const tasks = Array.from(taskList.querySelectorAll("li")) .filter((li) => li.id !== "persistent-task") .map((li) => li.firstChild.textContent) localStorage.setItem("tasks", JSON.stringify(tasks)); } function removeTaskFromLocalStorange(task) { const tasks = JSON.parse(localStorage.getItem("tasks") || "[]"); const updateTasks = tasks.filter((taskToDelete) => taskToDelete !== task); localStorage.setItem("tasks", JSON.stringify(updateTasks)); } ```
Aca les comparto mi codigo final, por si le quieren hechar un vistazo / alguna sugerencia JAVASCRIPT: ```js // Variables globales const taskButton = document.getElementById('main-button'); const mainInput = document.getElementById('main-input'); const main = document.getElementById('main-div'); const changeBack = document.getElementById('changeBackButton'); const body = document.getElementById('body'); let tasks = []; // Función para añadir las tareas tanto al DOM como al localStorage function addTask() { const task = mainInput.value.trim(); if (task) { createTaskElement(task); tasks.push(task); updateLocalStorage(); // Actualizamos el localStorage } else { alert('Please enter a task'); } mainInput.value = ''; // Limpiamos el input } // Función para crear los elementos de una tarea function createTaskElement(task) { const taskDiv = document.createElement('div'); const taskElement = document.createElement('p'); const otherFDiv = document.createElement('div'); const deleteP = document.createElement('p'); const editP = document.createElement('p'); deleteP.textContent = 'delete'; editP.textContent = 'edit'; otherFDiv.classList = 'other-functions'; taskElement.textContent = task; taskDiv.classList = 'task-section'; taskElement.classList = 'main-task'; deleteP.classList.add('delete'); editP.classList.add('edit'); // Añadimos cada uno a su respectivo contenedor padre main.append(taskDiv); taskDiv.append(taskElement); taskDiv.append(otherFDiv); otherFDiv.append(deleteP); otherFDiv.append(editP); } // Función para actualizar el localStorage function updateLocalStorage() { localStorage.setItem('tasks', JSON.stringify(tasks)); } // Función para cargar las tareas del localStorage function loadTasks() { const savedTasks = localStorage.getItem('tasks'); if (savedTasks && savedTasks.length > 0) { tasks = JSON.parse(savedTasks); tasks.forEach(createTaskElement); // Crea el DOM para cada tarea almacenada } } // Función para eliminar tareas function deleteTask(event) { const taskDiv = event.target.closest('.task-section'); const taskText = taskDiv.querySelector('.main-task').textContent; // Buscar el índice correcto y eliminar la tarea const index = tasks.indexOf(taskText); if (index > -1) { tasks.splice(index, 1); // Elimina la tarea del array updateLocalStorage(); // Actualiza el localStorage } taskDiv.remove(); // Elimina el div del DOM } // Función para editar tareas function editTask(event) { const taskDiv = event.target.closest('.task-section'); const taskElement = taskDiv.querySelector('.main-task'); const oldTask = taskElement.textContent; const newTask = prompt('Ingresa el nuevo texto:', oldTask); if (newTask === null || newTask.trim() === '') { alert('Please enter a valid task.'); return; } const index = tasks.indexOf(oldTask); if (index > -1) { tasks[index] = newTask; // Actualiza la tarea en el array updateLocalStorage(); // Actualiza el localStorage } taskElement.textContent = newTask; // Actualiza el texto en el DOM } // Eventos para eliminar y editar tareas main.addEventListener('click', function (event) { if (event.target.classList.contains('delete')) { deleteTask(event); } else if (event.target.classList.contains('edit')) { editTask(event); } }); // Evento para agregar tareas taskButton.addEventListener('click', addTask); // Evento para cambiar el fondo changeBack.addEventListener('click', function () { body.classList.toggle('dark'); main.classList.toggle('darkDiv'); const theme = body.classList.contains('dark') ? "dark" : "light" localStorage.setItem('theme', theme); }); const currentTheme = localStorage.getItem("theme") if (currentTheme === "dark") { body.classList.add("dark"); main.classList.add("darkDiv"); } else { body.classList.remove("dark"); main.classList.remove("darkDiv"); } // Cargar las tareas cuando la página se carga loadTasks(); ```HTML: ```js <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>To-do-list</title> <link rel="stylesheet" href="styles.css"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet"> </head> <body id="body"> <button id="changeBackButton">Change Theme</button> <main id="main">

Task Manager

<input type="text" placeholder="enter a task" id="main-input"> <button id="main-button">add task</button>
</main> </body> <script src="app.js"></script> </html> ``````js body { margin: 0; padding: 0; box-sizing: border-box; background-color: white; font-family: "Roboto", sans-serif; overflow: hidden; } #main { display: grid; place-items: center; height: 100vh; width: 100vw; } .main-div { background-color: whitesmoke; border-radius: 1px; width: 24vw; height: auto; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .title-container { background-color: #e5e5e5; display: flex; justify-content: center; align-items: center; text-align: center; flex-direction: row; margin: 15px; height: 50px; border-radius: 4px; border: transparent; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } .main-div h1 { font-size: 24px; font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif; font-weight: bold; } .label-div { background-color: #e5e5e5; height: 50px; display: flex; justify-content: center; align-items: center; margin: 10px; border-radius: 5px; border: transparent; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } .label-div input { width: 90%; margin: 10px; padding: 5px; border-radius: 5px; border: transparent; } .label-div button { background-color: dodgerblue; height: 25px; width: 100px; border-radius: 1px; border: transparent; margin: 5px; } .task-section { display: flex; justify-content: space-between; background-color: aliceblue; border-radius: 8px; border: transparent; margin: 10px; padding: 5px; align-items: center; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } .main-task { margin: 10px; } .main-task p { font-size: 18px; } .other-functions { margin: 10px; display: flex; } .other-functions p { margin: 5px; } .other-functions p:nth-child(1) { color: red; } .other-functions p:nth-child(2) { color: aqua; } #changeBackButton { margin: 5px; padding: 15px; background-color: #495057; color: white; border-radius: 5px; border: transparent; } .dark { background-color: #343a40 !important; } .darkDiv { background-color: #495057 !important; } ```Y CSS
Una pregunta, ¿No sería más viable usar el ClasName en lugar del ClassList al agregar la clase dark en la última linea, ya que el clasname reemplaza a la clase existente en lugar de agregarla otra clase con el ClassList?, tengo ahi la duda