Tutorial Paso a Paso: Crear una Aplicación de Notas con Vue.js y Local Storage
Crear una aplicación de notas sencilla es un excelente proyecto para quienes están empezando en el desarrollo frontend con Vue.js. En este tutorial Vue.js notas, te guiaré paso a paso para que puedas crear tu propia app para añadir, editar y eliminar notas, utilizando la potencia de Vue Reactive para gestionar el estado y Local Storage para guardar la información en el navegador.
¿Qué aprenderás en este tutorial?
- Configurar un proyecto Vue.js con Vue CLI
- Crear componentes para manejar notas (añadir, editar, eliminar)
- Gestionar el estado reactivo con Vue Reactive
- Implementar almacenamiento y recuperación de notas usando Local Storage
- Diseñar una interfaz limpia y funcional con CSS básico
Este es un proyecto Vue.js paso a paso perfecto para principiantes que desean entender cómo construir una aplicación completa y práctica.
1. Configuración Inicial del Proyecto con Vue CLI
Paso 1: Instalar Vue CLI
Si no tienes instalado Vue CLI en tu equipo, abre una terminal y ejecuta:
1 2 |
npm install -g @vue/cli |
Paso 2: Crear el Proyecto
Ejecuta para crear un proyecto llamado ‘app-notas’:
1 2 |
vue create app-notas |
Selecciona las opciones por defecto recomendadas (Vue 3, Babel, ESLint).
Paso 3: Navegar y Ejecutar
1 2 3 |
cd app-notas npm run serve |
Ahora abre http://localhost:8080
en tu navegador para verificar que el entorno está listo.
2. Estructura del Proyecto y Preparación
Vamos a trabajar principalmente en el archivo src/App.vue
y crear algunos componentes adicionales. Nuestra app tendrá dos componentes principales:
NotaForm
: formulario para añadir o editar notasListaNotas
: para mostrar la lista de notas con opciones para editar o eliminar
3. Gestión del Estado con Vue Reactive
Usaremos la API Composition con reactive
para manejar el estado global simple.
En src/App.vue
, importaremos y definirremos el estado para las notas.
4. Código Paso a Paso
4.1. Crear el Componente NotaForm
Crea un archivo llamado src/components/NotaForm.vue
con este contenido:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
<template> <form @submit.prevent="submitNota" class="nota-form"> <input type="text" v-model="contenido" placeholder="Escribe tu nota aquí" required autofocus /> <button type="submit">{{ editando ? 'Actualizar' : 'Añadir' }}</button> <button v-if="editando" type="button" @click="cancelar">Cancelar</button> </form> </template> <script setup> import { ref, watch, defineEmits, defineProps } from 'vue' const props = defineProps({ notaEdit: { type: Object, default: null, }, }) const emit = defineEmits(['guardar', 'cancelar-edicion']) const contenido = ref('') const editando = ref(false) watch( () => props.notaEdit, (nuevaNota) => { if (nuevaNota) { contenido.value = nuevaNota.contenido editando.value = true } else { contenido.value = '' editando.value = false } }, { immediate: true } ) function submitNota() { if (!contenido.value.trim()) return if (editando.value && props.notaEdit) { emit('guardar', { ...props.notaEdit, contenido: contenido.value }) } else { emit('guardar', { id: Date.now(), contenido: contenido.value }) } contenido.value = '' editando.value = false } function cancelar() { contenido.value = '' editando.value = false emit('cancelar-edicion') } </script> <style scoped> .nota-form { display: flex; gap: 10px; margin-bottom: 20px; } .nota-form input { flex-grow: 1; padding: 8px; border: 1px solid #ccc; border-radius: 4px; } .nota-form button { padding: 8px 16px; border: none; background-color: #42b983; color: white; border-radius: 4px; cursor: pointer; } .nota-form button[type="button"] { background-color: #888; } .nota-form button:hover { background-color: #369f6a; } </style> |
Explicación:
- El formulario se usa para añadir una nota nueva o editar una existente.
- La prop
notaEdit
determina si estamos en modo edición. - Emitimos eventos para que el componente padre maneje la acción de guardar o cancelar.
4.2. Crear el Componente ListaNotas
Crea src/components/ListaNotas.vue
con:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<template> <ul class="lista-notas"> <li v-for="nota in notas" :key="nota.id" class="nota-item"> <span>{{ nota.contenido }}</span> <div class="acciones"> <button @click="$emit('editar', nota)">Editar</button> <button @click="$emit('eliminar', nota.id)">Eliminar</button> </div> </li> </ul> </template> <script setup> import { defineProps, defineEmits } from 'vue' const props = defineProps({ notas: { type: Array, required: true, }, }) // Emitimos eventos para editar y eliminar const emit = defineEmits(['editar', 'eliminar']) </script> <style scoped> .lista-notas { list-style: none; padding: 0; margin: 0; } .nota-item { padding: 10px; background: #f9f9f9; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; } .nota-item span { flex-grow: 1; } .acciones button { margin-left: 10px; cursor: pointer; background-color: #42b983; border: none; color: white; padding: 6px 12px; border-radius: 4px; } .acciones button:last-child { background-color: #e74c3c; } .acciones button:hover { opacity: 0.85; } </style> |
Explicación:
- Listamos cada nota con botones para editar o eliminar.
- Emitimos eventos hacia el componente padre para manejar estas acciones.
4.3. Modificar src/App.vue
para gestionar estado y lógica
Reemplaza el contenido de src/App.vue
por:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
<template> <div id="app" class="container"> <h1>Aplicación de Notas con Vue.js y Local Storage</h1> <NotaForm :notaEdit="notaEditando" @guardar="guardarNota" @cancelar-edicion="cancelarEdicion" /> <ListaNotas :notas="notas" @editar="editarNota" @eliminar="eliminarNota" /> <p v-if="notas.length === 0">No tienes notas todavía. ¡Añade la primera!</p> </div> </template> <script setup> import { reactive, watch, onMounted } from 'vue' import NotaForm from './components/NotaForm.vue' import ListaNotas from './components/ListaNotas.vue' // Estado reactivo para notas y nota en edición const notas = reactive([]) const notaEditando = reactive({ value: null }) // Cargar notas desde Local Storage al iniciar onMounted(() => { const notasGuardadas = localStorage.getItem('notas') if (notasGuardadas) { const parsed = JSON.parse(notasGuardadas) parsed.forEach(nota => notas.push(nota)) } }) // Guardar notas en Local Storage cada vez que cambian watch( notas, (nuevasNotas) => { localStorage.setItem('notas', JSON.stringify(nuevasNotas)) }, { deep: true } ) function guardarNota(nota) { const index = notas.findIndex(n => n.id === nota.id) if (index !== -1) { // Actualizar nota existente notas[index].contenido = nota.contenido } else { // Añadir nueva nota notas.push(nota) } notaEditando.value = null } function editarNota(nota) { notaEditando.value = { ...nota } // Crear copia para evitar mutar directamente } function cancelarEdicion() { notaEditando.value = null } function eliminarNota(id) { const index = notas.findIndex(n => n.id === id) if (index !== -1) { notas.splice(index, 1) } } </script> <style> .container { max-width: 600px; margin: 40px auto; background: white; padding: 20px; border-radius: 6px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); font-family: Arial, sans-serif; } h1 { text-align: center; color: #35495e; margin-bottom: 20px; } p { padding: 15px; background-color: #eaf5f1; color: #555; border-radius: 4px; text-align: center; font-style: italic; } </style> |
Explicaciones importantes:
notas
es un arreglo reactivo para almacenar las notas.- Al montarse la app (
onMounted
), cargamos las notas guardadas en Local Storage. - Con
watch
observamos el arreglonotas
para actualizar Local Storage cada vez que cambie. - Definimos funciones para añadir/editar (
guardarNota
), seleccionar una nota para editar (editarNota
), cancelar la edición, y eliminar una nota. - La interfaz está organizada y permite interacciones fluidas.
5. Explicación de Local Storage
Local Storage es una forma sencilla de almacenar datos en el navegador que persisten aunque actualices o cierres la pestaña. Usamos:
localStorage.setItem('notas', JSON.stringify(notas))
para guardarlocalStorage.getItem('notas')
+JSON.parse()
para recuperar
Esto permite que las notas no se pierdan al cerrar la ventana, algo muy útil para apps simples.
6. Mejores Prácticas y Consejos
- Usa IDs únicos: Para las notas,
Date.now()
es un método rápido para generar IDs simples. - Manejo del estado: Para proyectos mayores, considera Vuex o Pinia, pero aquí
reactive
es suficiente. - Validaciones: Evita notas vacías con
required
y chequeos en el formulario. - Componentización: Mantén tu código modular, como en este proyecto que hemos dividido en componentes.
- Respetar accesibilidad: Usa etiquetas semánticas y placeholders claros.
7. Conclusión
¡Felicidades! Acabas de crear una aplicación Vue.js para principiantes funcional que permite gestionar notas con operaciones básicas y persistencia mediante Local Storage.
Este proyecto te ha enseñado a configurar un entorno Vue CLI, crear componentes reutilizables, manejar estado reactivo y trabajar con Local Storage paso a paso.
Te invito a seguir explorando las posibilidades de Vue.js, agregar nuevas funciones como categorías, búsqueda o etiquetas, o mejorar el diseño.
Si te ha gustado este tutorial Vue.js notas, compártelo y suscríbete para más contenido enfocado en ayudar a nuevos desarrolladores.
¡Manos a la obra! Abre tu editor favorito y empieza ahora mismo con este proyecto Vue.js paso a paso.