Unidad 7: Creación de Componentes en Vue.js
Objetivo: Aprender a crear y utilizar componentes en Vue.js para estructurar mejor nuestras aplicaciones, incluyendo el uso de props, gestión de estado local y la integración en un proyecto.
7.1 Introducción a los Componentes en Vue.js
¿Qué son los Componentes en Vue.js?
Los componentes son bloques reutilizables de código que encapsulan estructura (template), lógica (script) y estilos (style) en un solo archivo .vue. Permiten dividir una aplicación en partes más pequeñas y manejables, mejorando la organización y reutilización del código.
Ventajas de Usar Componentes
✅ Reutilización: Podemos usar el mismo componente en múltiples lugares.
✅ Mantenimiento: Separamos la lógica en archivos más pequeños y fáciles de gestionar.
✅ Modularidad: Cada componente puede manejar su propio estado y comportamiento sin afectar a otros.
✅ Legibilidad: Permiten una estructura clara del código, facilitando la colaboración en equipo.
7.2 Creación del Componente ToDoItem
📌 Explicación
Para estructurar mejor nuestra aplicación To-Do List, crearemos un componente ToDoItem.vue que representará cada tarea de la lista de manera independiente.
Cada tarea tendrá:
- Un texto que indica la descripción de la tarea.
- Un botón para eliminarla.
- Un checkbox para marcarla como completada.
Creamos un archivo ToDoItem.vue en la carpeta src/components con el siguiente contenido.
Dentro del componente crearemos una sección <template> y otra sección <script> con la lógica de Vue.js.
Ahora podemos empezar a añadir contenido a nuestro ToDoItem. Actualmente, las plantillas de Vue solo permiten un elemento raíz: un elemento debe contener todo dentro de la sección de la plantilla
Código de ToDoItem.vue
Ahora podemos añadir en un <div> el contenido de la tarea, incluyendo un checkbox y un label. De momento creamos un input genérico on un id y un texto genérico y fijo.
Código de ToDoItem.vue
Explicación del código:
<input type="checkbox" id="todo-item" />: Crea un checkbox para marcar la tarea como completada.<label for="todo-item">My Todo Item</label>: Muestra el texto de la tarea.
7.3. Usando ToDoItem en nuestra aplicación
De momento todo funciona bien pero aún no hemos añadido el componente a nuestra aplicación. Para ello, debemos importar el componente en ToDoList.vue y añadirlo a la lista de tareas.
En el archivo ToDoList.vue importamos el componente ToDoItem y lo añadimos en la parte superior de la etiqueta <script>.
Ahora dentro del objeto components añadimos el componente ToDoItem para que Vue lo reconozca.
Ahora para añadir el componente ToDoItem a la lista de tareas, debemos modificar el archivo ToDoList.vue y añadir el componente ToDoItem dentro de la etiqueta <ul>. Pero antes nos tenemos que detener en la nomencaltura. Podmemos ver que para nombrar el fichero de un componente y el componente se usa la notación PascalCase: ToDoItem.vue. Y el nombre del componente en el template se usa la notación kebab-case: to-do-item.
- kebap-case o lisp-case: Las palabras son separadas con guiones y en minúscula. Muy utilizado en lenguajes funcionales y scripts de terminal.
to-do-item. - camelCase: Las palabras son separadas con mayúsculas, salvo la primera letra que debe ir en minúscula. Muy utilizado en lenguajes orientados a objetos.
toDoItem. - PascalCase Todas las palabras empiezan con una mayúscula, incluyendo la primera letra. También es utilizado en lenguajes orientados a objetos, principalmente en la declaración.
ToDoItem.
Ahora en el fichero ToDoList.vue añadimos el componente ToDoItem dentro de la etiqueta <ul>.
Si ahora checkeamos nuestra web renderizada debemos ver lo siguiente:

7.3. Hacer que nuestro componentes sean dinámicos
Nuestro componente ToDoItem aún no es muy útil porque solo podemos incluirlo una vez en cada página (los ID deben ser únicos) y no tenemos forma de configurar el texto de la etiqueta. No es dinámico.
Lo que necesitamos es algún estado componente. Esto se puede lograr añadiendo accesorios a nuestro componente. Puedes pensar que los accesorios son similares a las entradas en una función. El valor de un accesorio le da a los componentes un estado inicial que afecta su visualización.
Registro de props
En Vue, hay dos formas de registrar las props:
- La primera forma es simplemente enumerar las
propscomo una matriz de cadenas. Cada entrada en la matriz corresponde al nombre de un accesorio. - La segunda forma es definir las
propscomo un objeto, con cada tecla correspondiente al nombre de la propiedad. Enumerar las propiedades como un objeto le permite especificar valores predeterminados, marcar las propiedades como necesarias, realizar la escritura básica de objetos (específicamente en torno a los tipos primitivos de JavaScript) y realizar una validación simple de los objetos.
Note
Nota: La validación de las prooiedades solo ocurre en el modo de desarrollo, por lo que no puede confiar estrictamente en ella en producción. Además, las funciones de validación de props se invocan antes de que se cree la instancia del componente, por lo que no tienen acceso al estado del componente (u otros accesorios).
Para el ejemplo utilizaremos el modo de registro de props como un objeto.
- Iremos al fichero
ToDoItem.vue. - Añadimos la propiedad
propsal objetodefault: {}que contiene un objeto vacío - Dentro del objeto añadimos las propiedades con las claves
labelydone. - Los valores de
labeldeben ser ubn objeto con dos propiedades (properties oprops).- El primero:
requiredque es un booleano que indica si la propiedad es requerida. En nuesrto caso serátrue. No podemos consentir una tarea sin texto. - El segundo:
typeque indica el tipo de dato que se espera. En nuestro caso seráString. Importante que la 'S' de 'String' sea mayúscula.
- El primero:
- La propiedad
donetambién será un objeto con dos propiedades.defaultque es el valor por defecto de la propiedad. En nuestro caso seráfalse. Esto significa que cuando no se pase un valor a la propiedaddonese asumirá que esfalse.typeseráBooleanporque es un tipo de dato que puede sertrueofalse.
7.4. Usando las propiedades registradas
Con estas propiedades definidas dentro del componente, podemos usar estos valores de variable en nuestra plantilla. Comencemos agregando la propiedad "label" a la plantilla del componente.
En el <template> reemplazamos el contenido de la etiqueta <label> con {{ label }}.
{{ }} es una sintaxis de plantilla especial en Vue que nos permite imprimir el resultado de las expresiones JavaScript definidas en nuestra clase, dentro de nuestra plantilla, incluyendo valores y métodos. Es importante saber que el contenido dentro de {{ }} se muestra como texto y no como HTML. En este caso, estamos imprimiendo el valor de la propiedad "label".
Ahora la sección <template>de nuestro componente debe quedar así:
Ahora si volvemos al nevagador para ver el renderizado como antes pero sin la etiqueta. Si vamos a DevTools de nuestro navegador veremos una advertencia:
[Vue warn]: Missing required prop: "label"
found in
---> <ToDoItem> at src/components/ToDoItem.vue
<App> at src/App.vue
<Root>
Esto se debe a que marcamos la etiqueta como una propiedad obligatoria, pero nunca se la asignamos al componente. Definimos dónde queremos que se use dentro de la plantilla, pero no la pasamos al componente al llamarlo. Vamos a solucionarlo.
Dentro del archivo ToDoList.vue, agrega una propiedad de etiqueta al componente
Ahora verá la etiqueta en su aplicación, y la advertencia no volverá a ser escupida en la consola.
Así que eso es un accesorio en pocas palabras. A continuación, pasaremos a cómo Vue persiste en el estado de los datos.
7.5. Objeto de datos en Vue (Vue's Data Object)
Si cambias el valor de la propiedad "label" pasada a la llamada <to-do-item></to-do-item> en tu componente App, deberías ver que se actualiza. Esto es genial. Tenemos una casilla de verificación con una etiqueta actualizable. Sin embargo, actualmente no estamos haciendo nada con la propiedad "done"; podemos marcar las casillas en la interfaz de usuario, pero en ninguna parte de la aplicación registramos si una tarea está realmente completada.
Para lograr esto, queremos vincular la propiedad "done" del componente al atributo "checked" del elemento <input>, de modo que sirva como registro de si la casilla está marcada o no. Sin embargo, es importante que las propiedades funcionen como enlace de datos unidireccional: un componente nunca debe alterar el valor de sus propias propiedades. Hay muchas razones para esto. En parte, la edición de propiedades por parte de los componentes puede dificultar la depuración. Si un valor se pasa a varios elementos secundarios, podría ser difícil rastrear de dónde provienen los cambios. Además, cambiar las propiedades puede provocar que los componentes se vuelvan a renderizar. Por lo tanto, mutar las propiedades de un componente provocaría que este se volviera a renderizar, lo que a su vez podría activar la mutación de nuevo.
Para solucionar esto, podemos gestionar el estado finalizado mediante la propiedad data de Vue. Esta propiedad permite gestionar el estado local de un componente; se encuentra dentro del objeto del componente junto con la propiedad props y tiene la siguiente estructura:
Observarás que la propiedad data es una función. Esto permite que los valores de los datos sean únicos para cada instancia de un componente en tiempo de ejecución; la función se invoca por separado para cada instancia del componente. Si declaras data como un simple objeto, todas las instancias de ese componente compartirían los mismos valores. Esto es un efecto secundario de la forma en que Vue registra los componentes y algo que no deseas.
Como es de esperar, esto se usa para acceder a las propiedades de un componente y a otras propiedades desde dentro de data. Veremos un ejemplo en breve.
Note
Nota: Debido a la forma en que esto funciona en las funciones flecha (vinculación al contexto del padre), no se podría acceder a ninguno de los atributos necesarios desde dentro de los datos si se usara una función flecha. Por lo tanto, no se debe usar una función flecha para la propiedad de datos.
Añadamos una propiedad data a nuestro componente ToDoItem. Esto devolverá un objeto con una sola propiedad llamada "isDone", cuyo valor es "this.done".
Vue hace algo de magia: vincula todas las propiedades directamente a la instancia del componente, por lo que no es necesario llamar a this.props.done. También vincula otros atributos (datos, que ya se han visto, y otros como métodos, calculados, etc.) directamente a la instancia. Esto se hace, en parte, para que estén disponibles para la plantilla. La desventaja es que es necesario mantener las claves únicas en estos atributos. Por eso llamamos a nuestro atributo data isDone en lugar de done.
Ahora necesitamos vincular la propiedad isDone a nuestro componente. De forma similar a cómo Vue usa expresiones {{ }} para mostrar expresiones JavaScript dentro de las plantillas, Vue tiene una sintaxis especial para vincular expresiones JavaScript a elementos y componentes HTML: v-bind. La expresión v-bind tiene este aspecto:
En otras palabras, se antepone v-bind: al atributo o propiedad que se desea enlazar. En la mayoría de los casos, se puede usar una abreviatura para la propiedad v-bind: simplemente anteponer dos puntos al atributo o propiedad. Por lo tanto, :attribute="expression" funciona igual que v-bind:attribute="expression".
En el caso de la casilla de verificación de nuestro componente ToDoItem, podemos usar v-bind para asignar la propiedad isDone al atributo marked del elemento <input>. Ambos son equivalentes:
Eres libre de usar el patrón que quieras. Sin embargo, es mejor mantenerlo consistente. Debido a que la sintaxis abreviada se usa más comúnmente, este tutorial se apegará a ese patrón.
Pruebe su componente pasando :done="true" a la llamada ToDoItem en App.vue. Tenga en cuenta que debe usar la sintaxis v-bind, ya que, de lo contrario, "true" se pasa como una cadena. La casilla de verificación mostrada debe estar marcada.
7.6. Dando a los elementos una identidad única
¡Genial! Ahora tenemos una casilla de verificación funcional cuyo estado podemos configurar programáticamente. Sin embargo, actualmente solo podemos agregar un componente ToDoList a la página porque el ID está codificado. Esto generaría errores con la tecnología de asistencia, ya que el ID es necesario para asignar correctamente las etiquetas a sus casillas de verificación. Para solucionar esto, podemos configurar el ID programáticamente en los datos del componente.
Podemos usar el método Crypto.randomUUID() para generar una cadena única y mantener los ID de los componentes únicos. randomUUID() está integrado en los navegadores modernos y proporciona una forma sencilla de garantizar la unicidad sin depender de bibliotecas externas.
A continuación, agregue un campo id a la propiedad data como se muestra a continuación; esto usa crypto.randomUUID() para devolver una cadena única, que luego prefijamos con "todo-":
7.7. Resumen
En este punto, tenemos un componente ToDoItem que funciona correctamente, al que se le puede pasar una etiqueta para mostrar, que almacenará su estado de verificación y se renderizará con un ID único cada vez que se llame. Puedes comprobar si los ID únicos funcionan añadiendo temporalmente más llamadas a <to-do-item></to-do-item> en App.vue y luego comprobando su salida renderizada con las DevTools de tu navegador.
Ahora estamos listos para añadir varios componentes ToDoItem a nuestra aplicación. En el próximo tema, veremos cómo añadir un conjunto de datos de elementos de tareas a nuestro componente App.vue, que luego recorreremos y mostraremos dentro de los componentes ToDoItem mediante la directiva v-for.
7.8 Tarea Práctica: Implementación en el Proyecto del Blog
📌 Objetivo: Crear un componente BlogPost.vue que represente una única entrada del blog con la capacidad de marcarla como "Importante".
📌 Pasos a seguir:
1️⃣ Crear el componente BlogPost.vue en la carpeta components/.
2️⃣ Usar props para pasar el título, contenido y el estado "importante" de la entrada.
3️⃣ Mostrar dinámicamente el título y el contenido de la entrada en la plantilla.
4️⃣ Agregar un checkbox que muestre si la entrada es "importante", pero sin modificar su estado (ya que aún no hemos visto eventos).
🔒 Solución del Blog (oculta inicialmente)
📌 Código de BlogPost.vue
Código de BlogPost.vue
📌 Código de BlogList.vue
Código de BlogList.vue
📌 Código de App.vue
Código de App.vue
📌 Explicación de la solución:
- Se ha agregado un checkbox que muestra si el post es "importante", pero no permite cambiarlo aún.
- El checkbox está vinculado con :checked="importante", lo que refleja su estado inicial.
- No hay eventos ni listas dinámicas (v-for), ya que aún no los hemos visto en la unidad.
- Solo se muestra una entrada fija, reflejando cómo pasar props a un componente.
- El App.vue importa BlogList.vue, que a su vez muestra un BlogPost.vue con los datos de una entrada fija.