Una aplicación To-Do List profesional que demuestra la implementación del patrón de diseño Modelo-Vista-Controlador (MVC) usando JavaScript vanilla, HTML5 y CSS3 con una arquitectura modular y escalable.
- ¿Qué es el Patrón MVC?
- Arquitectura del Proyecto
- Estructura de Carpetas
- Flujo de Datos
- Componentes Principales
- Características
- Instalación y Uso
- Tecnologías Utilizadas
- Comandos de Desarrollo
- Guía de Código
- Buenas Prácticas Implementadas
- Capturas de Pantalla
- Licencia
El Modelo-Vista-Controlador (MVC) es un patrón de diseño arquitectónico que separa una aplicación en tres componentes principales:
- Responsabilidad: Gestionar los datos y la lógica de negocio
- Características:
- No tiene conocimiento del DOM
- Es la única fuente de verdad de los datos
- Notifica a los observadores cuando los datos cambian
- En este proyecto:
TaskModel.js
- Responsabilidad: Presentar los datos al usuario (interfaz gráfica)
- Características:
- Renderiza el DOM
- Captura eventos del usuario (clicks, inputs)
- No contiene lógica de negocio
- En este proyecto:
TaskView.js
- Responsabilidad: Intermediario entre Modelo y Vista
- Características:
- Maneja la lógica de la aplicación
- Procesa las entradas del usuario
- Actualiza el Modelo y la Vista
- En este proyecto:
TaskController.js
- Separación de responsabilidades (Separation of Concerns)
- Código más mantenible y escalable
- Reutilización de componentes
- Facilita las pruebas unitarias
- Trabajo en equipo más eficiente
- Menor acoplamiento entre componentes
┌─────────────────────────────────────────────────┐
│ USUARIO │
│ (Interactúa con la interfaz) │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────┐
│ VISTA │ ◄─── Renderiza UI
│ (TaskView.js) │ Captura eventos
└────────┬────────┘
│
│ Eventos del usuario
▼
┌─────────────────┐
│ CONTROLADOR │ ◄─── Coordina
│(TaskController) │ Valida datos
└────────┬────────┘ Lógica de negocio
│
│ Actualiza
▼
┌─────────────────┐
│ MODELO │ ◄─── Gestiona datos
│ (TaskModel.js) │ Notifica cambios
└────────┬────────┘
│
│ Notifica cambios (Observer)
▼
┌─────────────────┐
│ STORAGE │ ◄─── Persiste datos
│ (Storage.js) │ localStorage
└─────────────────┘
proyecto-mvc-todo/
│
├── index.html # Punto de entrada HTML
├── README.md # Documentación del proyecto
├── app.js # Inicialización de la aplicación
│
├── assets/ # Recursos estáticos
│ └── img/ # Imágenes e íconos
│
├── src/ # Código fuente
│ ├── models/ # Capa de MODELO
│ │ └── TaskModel.js # Modelo de tareas
│ │
│ ├── views/ # Capa de VISTA
│ │ └── TaskView.js # Vista de tareas
│ │
│ ├── controllers/ # Capa de CONTROLADOR
│ │ └── TaskController.js # Controlador de tareas
│ │
│ └── utils/ # Utilidades
│ └── Storage.js # Gestión de localStorage
│
└── styles/ # Estilos modulares
├── main.css # Variables y estilos base
├── components.css # Componentes (botones, inputs)
├── layout.css # Estructura y layouts
└── responsive.css # Media queries
Usuario escribe "Comprar leche" y presiona Enter
↓
Vista captura el evento submit del formulario
↓
Vista llama a controller.handleAddTask("Comprar leche")
↓
Controlador valida el texto (no vacío, longitud máxima)
↓
Controlador llama a model.addTask("Comprar leche")
↓
Modelo crea la tarea, la agrega al array y notifica cambios
↓
Modelo ejecuta el callback onTasksChanged(tasks)
↓
Controlador recibe la notificación
↓
Controlador guarda en Storage y actualiza la Vista
↓
Vista re-renderiza la lista de tareas
↓
Usuario ve la nueva tarea en la interfaz
Usuario hace click en el checkbox
↓
Vista captura el evento change
↓
Vista obtiene el ID de la tarea y llama a controller.handleToggleTask(id)
↓
Controlador llama a model.toggleTask(id)
↓
Modelo cambia el estado de completed y notifica
↓
Controlador guarda y actualiza la Vista
↓
Vista re-renderiza con la tarea tachada
Métodos principales:
| Método | Descripción |
|---|---|
addTask(text) |
Agrega una nueva tarea |
deleteTask(id) |
Elimina una tarea por ID |
toggleTask(id) |
Alterna el estado completado/pendiente |
editTask(id, newText) |
Edita el texto de una tarea |
getFilteredTasks(filter) |
Obtiene tareas filtradas |
getStats() |
Obtiene estadísticas (total, completadas, pendientes) |
bindTasksChanged(callback) |
Vincula un observador para cambios |
Estructura de una tarea:
{
id: 1234567890,
text: "Comprar leche",
completed: false,
createdAt: "2025-01-15T10:30:00.000Z"
}Métodos principales:
| Método | Descripción |
|---|---|
displayTasks(tasks) |
Renderiza la lista de tareas |
updateCounters(stats) |
Actualiza los contadores |
updateFilterButtons(filter) |
Actualiza estado de botones de filtro |
bindAddTask(handler) |
Vincula el evento de agregar tarea |
bindDeleteTask(handler) |
Vincula el evento de eliminar |
bindToggleTask(handler) |
Vincula el evento de toggle |
bindEditTask(handler) |
Vincula el evento de editar |
bindFilterTasks(handler) |
Vincula el evento de filtrar |
Métodos principales:
| Método | Descripción |
|---|---|
handleAddTask(text) |
Maneja la adición de tareas (con validación) |
handleDeleteTask(id) |
Maneja la eliminación de tareas |
handleToggleTask(id) |
Maneja el cambio de estado |
handleEditTask(id, text) |
Maneja la edición (con validación) |
handleFilterTasks(filter) |
Maneja el filtrado de tareas |
onTasksChanged(tasks) |
Callback cuando el Modelo cambia |
Métodos principales:
| Método | Descripción |
|---|---|
saveTasks(tasks) |
Guarda tareas en localStorage |
getTasks() |
Recupera tareas de localStorage |
clearTasks() |
Elimina todas las tareas |
exportToFile() |
Exporta tareas a JSON |
importTasks(tasks) |
Importa tareas desde JSON |
- Agregar nuevas tareas
- Marcar tareas como completadas/pendientes
- Eliminar tareas (con confirmación)
- Editar tareas inline
- Filtrar tareas (Todas / Pendientes / Completadas)
- Contadores dinámicos
- Persistencia en localStorage
- Exportar/Importar datos (mediante consola)
- Patrón MVC puro
- JavaScript Vanilla (ES6+)
- Módulos ES6 (import/export)
- Patrón Observer/PubSub
- Single Responsibility Principle
- Código documentado en español
- Estilos CSS modulares
- Responsive design (mobile-first)
- Accesibilidad (ARIA labels)
# Navegar a la carpeta del proyecto
cd proyecto-mvc-todo
# Iniciar servidor HTTP (Python 3)
python -m http.server 8000
# Abrir en el navegador
# http://localhost:8000# Instalar http-server globalmente
npm install -g http-server
# Iniciar servidor
http-server -p 8000
# Abrir en el navegador
# http://localhost:8000- Instalar la extensión Live Server en VS Code
- Click derecho en
index.html - Seleccionar "Open with Live Server"
Simplemente abre index.html en tu navegador (algunos navegadores restringen módulos ES6 en archivos locales).
| Tecnología | Versión | Uso |
|---|---|---|
| HTML5 | - | Estructura semántica |
| CSS3 | - | Estilos modulares, variables CSS, Flexbox, Grid |
| JavaScript | ES6+ | Lógica de la aplicación, módulos ES6 |
| localStorage | Web API | Persistencia de datos |
Sin frameworks ni librerías - 100% JavaScript Vanilla
Abre la consola del navegador (F12) para usar estos comandos:
// Agregar tareas de demostración
addDemoTasks();
// Mostrar estado actual de la aplicación
showState();
// Exportar tareas a archivo JSON
exportTasks();
// Eliminar todas las tareas
clearAllData();
// Acceder al objeto de la aplicación
window.app.model // Acceder al Modelo
window.app.view // Acceder a la Vista
window.app.controller // Acceder al Controlador
window.app.storage // Acceder al StorageSupongamos que quieres agregar prioridades a las tareas (alta, media, baja).
addTask(taskText, priority = 'media') {
const task = {
id: this._generateId(),
text: taskText.trim(),
completed: false,
priority: priority, // ← NUEVA PROPIEDAD
createdAt: new Date().toISOString()
};
this.tasks.push(task);
this._commit(this.tasks);
return task;
}// Agregar un select para prioridad en el formulario
// Modificar el renderizado para mostrar la prioridad con coloreshandleAddTask(taskText, priority) {
// Validaciones...
this.model.addTask(taskText, priority);
}- Separación de responsabilidades (SoC)
- Single Responsibility Principle (SRP)
- Don't Repeat Yourself (DRY)
- Patrón Observer para comunicación
- Módulos ES6 (import/export)
- Clases ES6
- Arrow functions
- Template literals
- Destructuring
- Const/let (no var)
- Métodos privados (prefijo
_)
- Variables CSS (custom properties)
- Modularización por responsabilidad
- Naming conventions consistente
- Mobile-first design
- Transitions suaves
- Estructura semántica (
<header>,<main>,<section>,<footer>) - Atributos ARIA (accesibilidad)
- Meta tags apropiados
- Comentarios descriptivos
- ARIA labels
- Focus visible
- Roles ARIA
- Navegación por teclado
┌────────────────────────────────────────┐
│ To-Do List MVC │
│ Patrón Modelo-Vista-Controlador │
├────────────────────────────────────────┤
│ Total: 5 │ Pendientes: 3 │ OK: 2 │
├────────────────────────────────────────┤
│ [Todas] [Pendientes] [Completadas] │
├────────────────────────────────────────┤
│ [________Tarea nueva________] [+Add] │
├────────────────────────────────────────┤
│ [ ] Aprender MVC [E] [X] │
│ [X] Implementar CRUD [E] [X] │
│ [ ] Crear diseño [E] [X] │
└────────────────────────────────────────┘
Este proyecto es de código abierto y está disponible bajo la Licencia MIT.
MIT License
Copyright (c) 2025 Proyecto MVC Demo
Se concede permiso, de forma gratuita, a cualquier persona que obtenga
una copia de este software para usar, copiar, modificar, fusionar,
publicar, distribuir, sublicenciar y/o vender copias del Software.
Las contribuciones son bienvenidas. Por favor:
- Fork el proyecto
- Crea una rama para tu feature (
git checkout -b feature/AmazingFeature) - Commit tus cambios (
git commit -m 'Add some AmazingFeature') - Push a la rama (
git push origin feature/AmazingFeature) - Abre un Pull Request
Para preguntas o sugerencias sobre este proyecto educativo, no dudes en abrir un issue.
Si este proyecto te ayudó a entender el patrón MVC, considera darle una estrella
Hecho con dedicación para fines educativos