Índice de contenido
- ¿Que es Vue y para qué nos sirve?
- Características de Vue
- Vue en el contexto actual
- ¿Qué es una SPA?
- Formas de instalar/usar Vue
- Usando Vue mediante la CDN
- Creando un proyecto en Vue mediante Node
- Vue vs jQuery
- Algunos Pros de jQuery
- Algunos contras de jQuery
- Algunas ventajas de Vue
- ¿Por qué empezar a usar Vue?
- Reactividad en profundidad
- ¿Qué es la reactividad?
- Ejemplos de Vue: creando nuestras primeras aplicaciones
- Creación de un proyecto
- Estructura del proyecto
- Renderizado declarativo
- Vue en la práctica, app de contador
- Características principales de Vue - Opciones principales en el bloque de script
- Propiedad data, variables reactivas
- Method
- Propiedades Computadas (computed)
- ¿Por qué usarlas en lugar de métodos?
- Resumen del flujo de desarrollo
- Comunicación entre Componentes: Los props
- Validaciones y valores por defecto
- Ciclo de Vida del Componente en Vue
- Plugins y Extensibilidad
- Vue Router
- Axios
- Compartir datos entre componentes
- Condicionales
- v-if
- v-show
- Resumen
- v-for
- v-for con un objeto
- Reactividad en los arrays
- Ref()
- Símbolo de @ para importar componentes o archivos
- Comunicación entre Componentes
- Comunicación Padre → Hijo (props y refs)
- Comunicación Hijo → Padre (Eventos personalizados)
- Redibujado de Componentes: El truco de la key
- Binding de Estilos y Clases
- Contenido Dinámico con slots
- ️ Observadores (watch)
- Inyección de HTML: v-html
- ¿Options API o Composition API?
- Opciones principales en el bloque se template
- Impresiones
- V-model
- Gestión de Formularios y el modificador .prevent
- El problema de la recarga
- Eventos
- Alias Key
- Teclas modificadoras del sistema
- Eventos personalizados
- Opciones principales en el bloque de style
- Raw o renderizar HTML en Vue
- Alias para las importaciones en Vue
- Estilos locales y globales a los componentes scoped Vue
- Componente 1: Hello World
- Componente 2: Mi Primer Componente
- Definiendo el scope de estilos
- Vue devtools: Debug a tus apps
En esta entrada veremos los primeros pasos con este framework llamado Vue que es el boom de hoy en día, el framework JavaScript que está más de moda; daremos un vistazo rápido a las características de Vue, donde instalarlo, como descargar Vue, haremos una sencilla comparación de Vue con jQuery y posteriormente daremos unos pequeños ejemplos para empezar a trabajar con Vue.
¿Que es Vue y para qué nos sirve?
Vue es un Framework progresivo, lo que significa que sirve para consumir la interfaz del usuario; fue creado por Evan You que trabajaba en Google para ese entonces; Vue surgió en el año 2014, como puedes ver es un framework reciente con "poco" tiempo en el mercado pero que está muy pulido, cuenta con una buena acogida por los usuarios, una comunidad creciente, buena documentación y facilidades de uso que no requieren ni siquiera usar Node para emplearlo lo que es una gran ventaja que tiene con respecto a la competencia.
Características de Vue
Vue es un framework progresivo, lo que significa que podemos emplearlo para algo muy básico, igual que jQuery o sistemas más grandes y complejos y en general cuenta con un rendimiento muy bueno para lo poco que pesa:
- Vue es un framework accesible que está a la disposición de todos mediante código libre.
- Es un framework muy pequeños que nos facilita enormemente la interacción con la interfaz o el HTML.
- Optimizado; su núcleo es muy pequeño y ocupa unos 70Kb lo que es bastante liviano.
- Como indicamos antes, cuenta con una comunidad creciente y buena documentación con una curva de aprendizaje baja ya que es sencillo de emplear y muy conciso.
Vue es otro framework que tenemos para JavaScript que, en su momento, logró hacerse un hueco entre los dos grandes que dominaban el panorama: Angular y React.
Esto ocurrió principalmente porque Vue es:
- Un framework ligero.
- Versátil.
- Con una curva de aprendizaje menor.
- Y, en definitiva, más fácil para comenzar en el mundo de los frameworks modernos.
Vue en el contexto actual
Hablo un poco en pasado porque hoy en día también tenemos otros frameworks modernos, por ejemplo:
- Svelte
- Astro
Sin embargo, Vue sigue siendo una excelente opción para desarrollar todo tipo de aplicaciones web. Sigue siendo un framework moderno y cuenta con:
- Todas las características necesarias para crear SPA (Single Page Applications).
- Una gran cantidad de plugins para extender su funcionalidad fácilmente.
Aunque hoy existen alternativas algo más modernas como Svelte o Astro, Vue sigue siendo una excelente opción para cualquier desarrollo. Es un framework moderno que posee todas las características necesarias para crear SPAs (Single Page Applications) y cuenta con un ecosistema robusto de plugins para extender sus funcionalidades.
<template>
<div>
<div v-if="loading">
Cargando...
</div>
<div v-else>
<h1>¡Contenido listo!</h1>
</div>
</div>
</template>
<script>
export default {
// 1. Aquí definimos nuestras variables (el estado)
data() {
return {
loading: true
};
},
// 2. Aquí ejecutamos lógica cuando el componente se carga
mounted() {
// Simulamos una espera de 2 segundos
setTimeout(() => {
this.loading = false; // "this" accede a la variable de arriba
}, 2000);
}
};
</script>Cuando loading es true, significa que la aplicación está cargando datos.
Entonces mostramos un loader.
Cuando loading cambia a false, Vue automáticamente:
- Detecta el cambio.
- Actualiza la interfaz.
- Muestra el contenido.
Todo esto sin que tengamos que manipular el DOM manualmente.
¿Qué es una SPA?
Una SPA (Single Page Application) es una aplicación web que:
- Carga todo lo necesario la primera vez (HTML, CSS y JavaScript).
- Luego solo realiza peticiones a una API para obtener datos dinámicos.
Es decir:
- Se carga la aplicación.
- A partir de ahí, todo se actualiza dinámicamente sin recargar la página.
Aunque también es posible que toda la información esté local en la misma aplicación, sin necesidad de consumir una API. Todo depende de cómo quieras implementarla.
Formas de instalar/usar Vue
Hay muchas formas de crear un proyecto en Vue, podemos usar la opción de CDN, que es ideal cuando queremos experimentar un poco con el framework o hacer proyectos pequeños o con alcance limitado y mediante la Vue CLI y Node; de esto, hablaremos en los siguientes apartados.
Vue es tan versátil que podemos incluirlo no sólo como parte de una solución, es decir, que gobierne una página completa:

Si no, podemos incluirlo como parte de una aplicación existente, es decir, que no esté desarrollada en Vue y es por eso que se conoce como progresivo:

Es decir, que no tenemos que tener una aplicación web definida con Vue en el 100% de la página o la totalidad de la misma; podemos especificar que solamente un contenedor (por ejemplo, un DIV) sea el único que va a controlar Vue.
Usando Vue mediante la CDN
Está opción de instalación es la más simple, pero, la menos escalables ya que perdemos todas las ventajas que tenemos en un proyecto en Node, como su inmensa cantidad de plugins y gestión de los paquetes mediante NPM; pero, es la mejor opción si queremos realizar proyectos con alcance limitados o de pruebas; para ello, agregamos en una página HTML la dependencia de Vue:
<script src="https://unpkg.com/vue@next"></script>Creando un proyecto en Vue mediante Node
Comencemos creando un proyecto en Node mediante:
$ npm initPreguntará información base como:
name: (project-name) <project-name>
version: <0>
description: <The Project Description>
entry point: <//leave empty>
test command: <//leave empty>
git repository: <//the repositories url>
keywords: <//leave empty>
author: <// your name>
license: <N/A>Nos movemos dentro del nuevo proyecto:
cd <project-name>Y agregamos Vue mediante:
$ npm install vueCon esto, instalamos la última versión del framework en el proyecto que creamos anteriormente.
Tienes más información en:
Vue vs jQuery
Lo primero que tienes que tener en cuenta es que son dos mundos apartes, dos paradigmas diferentes que buscan hacer lo mismo, aplicaciones webs de manera sencilla, jQuery cuenta con una inmensa cantidad de plugins y nos da ese plus que no tenemos con JavaScript nativo y Vue también nos da una importante cantidad de plugins y nos permite ganar en organización, optimizando a nivel de código hasta el mínimo para hacer cosas que son generales como veremos a continuación.
Hay muchas razones por las cuales podemos emplear framework como Vue que son progresivos en vez de jQuery o frameworks similares; Vue nos ofrece una organización mayor (aunque en la práctica jQuery no nos ofrece ninguna organización ni patrón de desarrollo) a la que nos ofrece jQuery, son códigos más fáciles de entender y de mantener ya que cuenta con componentes y el patrón te templates de Vue que vimos en la sección anterior; un punto muy fuerte es como veremos en otras entradas de Vue es la potente interacción en base a eventos, podemos establecer modelos o variables en Vue y atarlas a un elemento en HTML y modificarlo en donde queramos, es decir si modificamos la variable desde JavaScript, este cambio se verá reflejado en la variable; lo mismo ocurre si lo modificamos en un elemento HTML.
Podemos referenciar variables en el HTML como si un template se tratase y este se imprimirá y actualizará en tiempo real si la variable sufre cambios sin que nosotros hagamos algo.
Ya queda por tu parte imaginarte cómo hacer esto con JavaScript nativo o jQuery, que aunque no es una tarea complicada, como verás en la sección de ejemplos en Vue es algo nativo y funciona muy bien.
Podemos imprimir arreglos fácilmente y desde el mismo HTML empleando unas cláusulas especiales que el mismo Vue procesa internamente, en el caso de jQuery tendríamos que iterar todo mediante un for o each dentro del bloque script
A la final una tecnología no tiene porqué solapar a la otra, todo depende del proyecto que lleves a cabo y de acoplar de manera inteligente una u otra tecnología, inclusive las dos sin ningún problema.
Algunos Pros de jQuery
- Poder realizar peticiones Ajax fácilmente.
- Un set de animaciones extensible mediante plugins.
- Miles de plugins a tu disposición.
Algunos contras de jQuery
- Debes de manejar cada elemento HTML independientemente.
- El sistema de renderizado (mostrar contenido en HTML) es lo típico y algo obsoleto comparado con otras tecnologías.
- Es un dolor de cabeza cuando la aplicación crece, ya que carece de organización.
Algunas ventajas de Vue
- Estupendo sistema para renderizar de JavaScript a HTML como si de una plantilla se tratase.
- Curva de aprendizaje baja.
- Organización mediante componentes.
- Extensible mediante componentes.
¿Por qué empezar a usar Vue?
Como mencionamos antes, no debemos de aferrarnos a una tecnología u otra, cada una de ellas tiene sus ventajas y sus desventajas se pueden hacer las mismas cosas desde distintas formas así que dependiendo de lo que quieras hacer selecciona una u otra tecnología; Vue nos permite ganar tiempo al momento de crear aplicaciones con las cuales vamos a manipular bastante el DOM del HTML debido a como está concebido, pero hay muchas otras herramientas más específicas que puedes emplear también dependiendo de lo que desees realizar.
Reactividad en profundidad
¡Ahora es el momento de sumergirse en profundidad! Una de las características más distintivas de Vue es el sistema de reactividad discreto. Los modelos son objetos de JavaScript con proxy. Cuando los modifica, la vista se actualiza. Hace que la administración del estado sea simple e intuitiva, pero también es importante comprender cómo funciona para evitar algunos errores comunes. En esta publicación, vamos a conocer algunos de los detalles de la reactividad de Vue.
¿Qué es la reactividad?
La reactividad está ligada a las propiedades que definimos en las opciones de data; Vue irá detectando cada vez que modificamos dichas propiedades.
Cada una de estas propiedades, tiene un watcher interno al framework que detecta cuando existen cambios en la misma y al detectar, dispara la opción de render (del template) dando como resultado que vemos los cambios reflejados en esa propiedad en la lógica que tengamos definida en nuestro template; es importante señalar, que el proceso de render es ejecutado SOLO si los cambios en la propiedad afectan al template;
En la práctica tenemos un proceso muy optimizado al momento en el que Vue actualice el DOM (template).
Gracias a la reactividad, no necesitamos manipular el DOM manualmente. Si declaramos una variable en nuestro estado, Vue estará atento a cualquier cambio en su valor para actualizar automáticamente la interfaz.
Por ejemplo, si tenemos una variable loading, cuando su valor pase de true a false tras consumir una API, Vue detectará el cambio y pintará el componente automáticamente. Esto ahorra horas de lógica manual y propensa a errores.
Ejemplos de Vue: creando nuestras primeras aplicaciones
En esta sección veremos cómo emplear lo básico de Vue, se les recuerda que Vue como framework que es puedes expandir sus funcionalidades mediante plugins y cuenta con su propio sistema de líneas de comandos mediante Vue Clic, pero podemos hacer cosas realmente interesantes con Vue empleando un mínimo de JavaScript .
Creación de un proyecto
A diferencia de versiones antiguas, hoy no necesitamos instalaciones globales complejas. Simplemente utiliza el comando oficial en tu terminal:
$ npm create vue@latestDespués de crear el proyecto debemos instalar las dependencias:
$ npm installEsto descargará todas las librerías necesarias dentro de:
node_modulesEstructura del proyecto
Una vez creado, es fundamental ejecutar npm install para descargar las dependencias y, posteriormente, npm run dev para levantar el servidor de desarrollo.
- package.json: Define los scripts y las dependencias del proyecto.
- src/: Carpeta principal donde reside nuestro código fuente.
- main.js: El archivo de arranque donde montamos la aplicación en un elemento HTML (normalmente un div con id="app").
Y servir el proyecto mediante:
$ npm run serveAl ejecutar este comando, veremos una salida como la siguiente:
> bases@0.0.0 dev
> vite
VITE v7.3.1 ready in 8415 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ Vue DevTools: Open http://localhost:5173/__devtools__/ as a separate window
➜ Vue DevTools: Press Alt(⌥)+Shift(⇧)+D in App to toggle the Vue DevTools
➜ press h + enter to show helpRenderizado declarativo
Como una característica muy potente, Vue cuenta con su propio sistema de renderizado en el que en el HTML que definimos el ámbito de Vue, podemos renderizar valores de variables declaradas JavaScript y referenciadas en HTML como vemos a continuación:
<div id="app">
<h1>{{message}}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: "Hola Vue"
}
})
</script>Esto nos da la siguiente salida:

Como puedes ver es una característica muy potente de Vue, hoy en día que recibimos datos de todas partes, podemos referenciar fácilmente variables, ganando legibilidad y organización en JavaScript como nunca.
Podrías pensar algo como "Ok ok podemos imprimir variables en el HTML con unas llaves que mas puede hacer".
Vue en la práctica, app de contador
Partiendo del proyecto que creamos en el apartado anterior, ahora que conocemos las características básicas de Vue de manera teórica, vamos a conocerlo en la práctica creando nuestra primera aplicación en Vue que será un contador, cuando presionemos un botón un contador aumenta en una unidad; para ello, agregamos el siguiente código:
Características principales de Vue - Opciones principales en el bloque de script
En este apartado vamos a conocer las características principales del framework con las cuales creamos los componentes en Vue
En el apartado anterior, vimos cómo crear un sencillo ejemplo en la cual vimos los aspectos más básicos del framework, en este apartado, profundizaremos más en los conceptos que vimos antes e introduciremos algunos nuevos; específicamente, todas las opciones que veremos en este apartado son implementados en el apartado de script:
<script>
export default {
***
}
</script>Propiedad data, variables reactivas
La opción de data retorna el estado inicial del componente, es decir, un conjunto de variables reactivas que podemos emplear a lo largo del componente, ya sea en la sección de script o en el template.
La opción de data es la más importante es un componente en Vue, al menos la más empleada ya que es el corazón de un componente, en la misma, mediante la definición de una función retorna un objeto que contiene las variables reactivas que se pueden emplear en el componente, específicamente, desde el template imprimiendo las mismas con la sintaxis doble llave {{}}:
<script>
export default {
data: function(){
return {
counter:0
}
},
}
</script>Esta opción es una función que retorna un objeto que contiene los datos que se utilizan en el componente y se puede acceder a ellos desde cualquier lugar del componente. Por ejemplo, si desea definir un objeto de datos llamado message, puede hacerlo de la siguiente manera:
<script>
export default {
data: function(){
return {
message: ""
}
},
}
</script>En este ejemplo, hemos definido un componente con un objeto que contiene una variable llamada message. La variable message se utiliza en la plantilla del componente para mostrar un mensaje. Anteriormente vimos un ejemplo en el cual, al darle click a un botón, se actualiza la variable reactiva llamada counter.
En este ejemplo, se define un objeto de datos llamado message que contiene una cadena de texto. Este objeto se puede utilizar en cualquier lugar del componente, como en la template o en los métodos.
Method
La sección methods de una aplicación Vue es donde se definen los métodos que se utilizan en la instancia de Vue; la utilidad de los métodos son muchas, usarlas al inicio de la creación de un componente para inicializar el componente o como respuestas a eventos, por ejemplo, al dar un click sobre un botón, evento submit de un formulario, entre otros.
A la final la sección de methods como indica su nombre podemos definir múltiples métodos, tantos como necesite el componente:
<script>
export default {
methods: {
showAlert: function () {
alert('¡Hello world!')
}
}
}
</script>Propiedades Computadas (computed)
Las propiedades computadas son una característica bastante importante de Vue y nos permiten crear otras propiedades que se calculan a partir de otras propiedades o las variables reactivas en en caso de Vue; de esta forma, podemos evaluar condiciones complejas de manera eficiente y conservando la reactividad de Vue.
¿Por qué usarlas en lugar de métodos?
Aunque parezcan funciones, se utilizan como propiedades/variables (sin paréntesis ()).
- Sintaxis: Se definen en un bloque computed dentro de tu objeto de exportación.
- Eficiencia: A diferencia de los métodos, las propiedades computadas se almacenan en caché. Solo se recalculan si alguna de las dependencias reactivas cambia.
- Ejemplo: Si tienes un texto y necesitas revertirlo, el computed lo hará de forma limpia y eficiente.
- Cache: A diferencia de los métodos (methods), las propiedades computadas se almacenan en caché. Si los datos de los que dependen (como message) no cambian, Vue devolverá el resultado guardado sin volver a ejecutar la lógica, optimizando procesos pesados.
- Reactividad: Cuando una variable de la que depende la propiedad computada se actualiza (por ejemplo, mediante un setTimeout), Vue detecta el cambio automáticamente y vuelve a calcular el valor de la propiedad, reflejándolo en el DOM.
- Uso: Son ideales para transformar listados, realizar filtros o procesar datos antes de mostrarlos, permitiendo invocarlas como si fueran simples propiedades ({{ mensajeInvertido }}) en lugar de funciones ({{ mensajeInvertido() }}).
src\components\ComputedComponent.vue
<template>
{{ reversedMessage }}
{{ reversedMessage }}
{{ reversedMessage }}
{{ reversedMessageMethod () }}
</template>
<script>
export default {
data: function () {
return {
message: "Hola Mundo 1"
}
},
methods: {
reversedMessageMethod: function () {
// console.log('reversedMessageMethod')
setTimeout(()=>{
this.message = 'Hola Mundo 2'
}, 3000)
return this.message.split('').reverse().join('')
}
},
computed: {
reversedMessage: function () {
console.log('reversedMessage')
return this.message.split('').reverse().join('')
}
}
}
</script>Resumen del flujo de desarrollo
- data(): Donde reside tu estado (variables reactivas).
- methods: Donde reside la lógica de ejecución (eventos, llamadas a API).
- computed: Donde reside la lógica de transformación de datos (datos derivados de otros).
- v-model: El puente para capturar la interacción del usuario en tiempo real.
Este enfoque modular y expresivo es lo que hace que Vue sea tan potente. Al separar la lógica de la vista y automatizar la reactividad, nos olvidamos de la manipulación manual del DOM, permitiéndonos enfocarnos en lo que realmente importa: la funcionalidad de nuestra aplicación.
Como puedes apreciar las propiedades computadas son realmente funciones en las cuales se le establecen comparaciones u otra lógica elaborada, en este ejemplo, invertir una cadena de texto; en la propiedad computada anterior colocamos una impresión por consola:
src\components\ComputedComponent.vue
reversedMessage: function () {
console.log('reversedMessage')
return this.message.split('').reverse().join('')
}Y desde el template, empleamos la propiedad computada como si se tratara de una variable reactiva en Vue; puedes ver que imprimimos la misma varias veces en el template, específicamente, 3 veces:
<template>
<ul>
<li> {{ reversedMessage }} </li>
<li> {{ reversedMessage }} </li>
<li> {{ reversedMessage }} </li>
</ul>
</template>Sin embargo, si inspeccionamos la consola, veremos que solamente aparece una sola impresión:
reversedMessagePodemos decidir que la función de la propiedad computada se imprimió una sola vez, como comentamos antes, la propiedad computada solamente se evalúa una vez sin importar las veces que se emplee la propiedad computada y solamente se volverá a ejecutar cuando alguno de los valores que contiene la misma cambia, en este ejemplo sería la variable message.
Si variamos la misma, operación que podemos hacer mediante el v-model, por ejemplo para agregar una letra más, veremos que la propiedad computada se vuelve a invocar, pero, solamente una vez:
<template>
<ul>
<li> {{ reversedMessage }} </li>
<li> {{ reversedMessage }} </li>
<li> {{ reversedMessage }} </li>
</ul>
<input type="text" v-model="message">
</template>Por el contrario, si empleamos un método en su lugar, veríamos que se innova tantas veces referenciamos el mismo en el template:
<template>
<ul>
<li> {{ reversedMessageByMethod() }} </li>
<li> {{ reversedMessageByMethod() }} </li>
<li> {{ reversedMessageByMethod() }} </li>
</ul>
</template>Entonces, en definitiva, si necesitas realizar operaciones sobre alguna variable reactiva de Vue, el uso de las propiedades computadas son tu mejor opción no solamente por su eficiencia si no porque permiten hacer una separación entre la lógica que siempre debería estar en la sección de script y el template.
Más información en:
https://vuejs.org/guide/essentials/computed.html
Comunicación entre Componentes: Los props
Los props son el mecanismo estándar para pasar datos de un componente padre a un componente hijo.
- Definición: En el componente hijo, declaramos el objeto props para especificar qué datos esperamos recibir y qué tipo de dato son (String, Number, etc.).
- Paso de datos: Desde el padre, pasamos los datos mediante atributos personalizados.
- Estáticos: message="Hola"
- Dinámicos: :message="nombreVariable" (Usar los dos puntos : es crucial para que Vue evalúe la expresión como una variable y no como un texto plano).
- Validaciones: Puedes configurar los props como objetos complejos para añadir validaciones, definir si son requeridos (required: true) o establecer valores por defecto (default).
Como se comentó anteriormente, muchas veces es necesario pasar datos entre componentes, Vue es una tecnología modular en la cual se construyen cada uno de los elementos de interfaz gráfica mediante componentes, específicamente de un componente padre a un componente hijo.
Las propiedades se definen en el objeto props de un componente y se pasan al componente hijo como atributos personalizados.
Los props se pueden utilizar para pasar datos simples como cadenas y números, así como objetos y matrices más complejos.
En la mayoría de los casos es necesario pasar datos entre componentes para poder construir correctamente los elementos de interfaz gráfica y con esto que la aplicación funcione como se espera; el uso de los props es la forma predeterminada que tenemos para comunicar entre componentes.
Los props no son más que atributos que definimos a nivel del componente cuando instanciamos el mismo desde el componente padre; por ejemplo:
src\components\props\ParentComponent.vue
<template>
<div>
<h1>{{ title }}</h1>
<ChildComponent :message="message" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent,
},
data() {
return {
title: 'Props in Vue',
message: 'Data from parent',
};
},
};
</script>Y los mismos deben de estar registrados en el componente hijo:
src\components\props\ChildComponent.vue
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
props: {
message: String,
},
};
</script>Los componentes de Vue requieren una declaración explícita de props para que Vue sepa cuales props serán pasados al componente.
Hay varias opciones disponibles con los props, podemos definir los props que vamos a recibir como un array:
props: ['foo'],Validaciones y valores por defecto
O una mejor opción, es especificando como si fuera un objeto en la cual se puede especificar datos sobre los props, como el tipo de dato:
export default {
props: {
title: String,
likes: Number
}
}Como puedes apreciar, aparte de indicar el nombre del atributo/prop, también se especifica el tipo de dato; también, podemos definir una serie de opciones para los props como un valor por defecto:
export default {
props: {
title: {
default: 'Title'
},
}
}Validaciones para indicar el formato u otro:
export default {
props: {
title: {
validator(value, props) {
return value.length > 5
}
},
}
}En el cual, puedes colocar cualquier tipo de validación y si el prop no pasa las validaciones, verás una excepción por la consola del navegador como la siguiente:
main.js:4 [Vue warn]: Invalid prop: custom validator check failed for prop "message".
at <ChildComponent message="Data from parent" >
at <ParentComponent>
at <App>O si es requerido o puede ser nulo:
export default {
props: {
title: {
type: String,
required: true
},
}
}O un tipo de dato por defecto:
export default {
props: {
title: {
type: String
},
}
}Ciclo de Vida del Componente en Vue
Los ciclos de vida de la aplicación de Vue son fundamentales para que podamos crear componentes de manera efectiva, en esencia, el ciclo de Vue son representamos por funciones que podemos emplear en los componentes para cuando se crea el componente, se elimina, entre otros:
export default {
mounted() {
console.log(`the component is now mounted.`)
}
}Por ejemplo, una operación muy común es que, cuando se carga el componente, queremos inicializar los datos conectándonos a alguna API.
Supón que tenemos un componente de listado el cual se construye a partir de un JSON array provisto por una Api Rest la cual se debe de consumir al momento de cargar el componente, en estos casos, podemos emplear la función de mounted():
export default {
mounted() {
this.$axios.get(url).then((res) => {
this.dataList = res.data;
});
}
}Cada componente en Vue atraviesa una serie de etapas desde que nace hasta que es destruido. Puedes "engancharte" a estos eventos mediante métodos especiales:
- created(): Se ejecuta cuando el componente ha sido creado. Útil para lógica inicial, aunque aún no hay acceso al DOM.
- mounted(): El componente ya está insertado en la página. Es el punto ideal para llamadas a APIs o inicialización de librerías externas.
- beforeUnmount() / unmounted(): Ideal para realizar limpiezas, cerrar sesiones o cancelar suscripciones antes de que el componente sea eliminado para ahorrar recursos.
src\components\LifecycleHooksComponent.vue
<template>
</template>
<script>
export default {
beforeCreate(){
console.log('beforeCreate');
},
created(){
console.log('created');
},
mounted(){
console.log('mounted');
},
beforeDestroy(){
console.log('beforeDestroy');
},
destroyed(){
console.log('destroyed');
},
data: function(){
return {
}
},
methods: {
},
}
</script>Plugins y Extensibilidad
Vue tiene una cantidad inmensa de plugins que tenemos disponibles para realiza toda clase de operaciones.
Vue es altamente extensible mediante el método .use(). Cuando creamos nuestra instancia de aplicación en main.js, podemos instalar plugins globales (como Pinia para el estado o Axios para peticiones HTTP) de forma centralizada.
Los plugins en Vue, usualmente tienen una configuración como la siguiente:
src\main.js
import PLUGIN from 'PLUGIN';
const app = createApp(App)
app.use(PLUGIN) // Registro global
app.mount('#app')En donde, en el archivo que se crea la aplicación en Vue, se emplea la función de use(), para registrar el plugin y con esto, poder emplear las características del plugin que hayamos instalado, a lo largo del libro, instalaremos algunos plugins para potenciar la experiencia.
Vue Router
Por defecto, al crear una aplicación en Vue, solamente tenemos una página, es decir, no podemos navegar a otras ventanas de la aplicación y es aquí donde entran plugins como Vue Router que es el enrutador oficial de Vue.js, es decir, es el que nos permite crear páginas para poder navegar entre distintas páginas que a la final, son componentes en Vue.
Vue Router no forma parte de Vue y se debe de instalar mediante una dependencia, es decir, un plugin; Vue Router fue desarrollado por el mismo equipo que desarrolló Vue por lo tanto, su integración es perfecta con el framework.
Algunas de las características de Vue Router incluyen:
- Mapear rutas de manera anidadas.
- Enrutamiento dinámico.
- Configuración de enrutador modular y basado en componentes.
- Parámetros de ruta, consulta, comodines o almohadillas.
- Efectos de transición entre vistas.
Vue Router lo emplearemos más adelante y por lo tanto, veremos una adaptación práctica del plugin.
Axios
Otra biblioteca que no puede faltar es la de axios, que es la biblioteca empleada por excelencia para realizar solicitudes HTTP, es decir, para hacer peticiones GET, POST, PUT, PATCH o DELETE y es una alternativa a la API incorporará en los navegadores webs modernos mediante la función de fetch(); algunas ventajas que tenemos al usar axios en vez de fetch():
- Sintaxis más simple: Axios ofrece una sintaxis más simple y fácil de emplear; en axios ya existen métodos que tienen su equivalente con la petición HTTP como lo son axios.get() o axios.post().
- Interceptores de solicitud y respuesta: Axios permite agregar interceptores a las solicitudes y respuestas HTTP. Esto significa que puede agregar lógica personalizada para manejar errores, autenticación, etc.
- Transformación automática de datos a formato JSON que es el formato más empleado para compartir datos en las API RESTs.
- Compatibilidad con navegadores antiguos, al ser una biblioteca que se instala en un proyecto de JavaScript, es posible emplearlo en una gran cantidad de navegadores en donde el fetch no es soportado.
Axios ni es un plugin específico para Vue, si no, para JavaScript, es posible emplearlo mediante Node o similares o mediante la CDN, más adelante mostraremos cómo emplear esta biblioteca.
Compartir datos entre componentes
Existen dos formas predeterminadas para poder compartir datos entre componentes, el que tenemos por defecto es el de los props, que presentamos anteriormente, pero, también podemos emplear plugins adicionales como el de Vuex o Pinia que son manejadores de estados.
Un manejador de estados es una herramienta que se utiliza en el desarrollo de aplicaciones para manejar el estado de la aplicación.
El estado de una aplicación corresponde a los datos que se manipulan y modifican en la misma, mientras la aplicación se ejecuta.
Al igual que Vue Router, son plugins creados específicamente para Vue y en el capítulo 5 veremos cómo emplear Pinia como manejador de estado.
Condicionales
En Vue, existen dos formas de emplear condicionales mediante las directivas v-if y v-show; ambas, son directivas que permiten evaluar condiciones de verdadero y falso para mostrar u ocultar elementos HTML.
La principal diferencia entre ambas es que v-if elimina el elemento del DOM si la expresión es falsa, mientras que v-show simplemente lo oculta el mencionado elemento.
v-if
Al igual que en Vanilla JavaScript podemos emplear condicionales en los templates cuyos usos son iguales a los que hacemos en vanilla JavaScript, pero, estos los podemos establecer en los templates de la siguiente manera:
<template>
<h4 v-if="true">Is True</h4>
</template>Para hacerlo más interesante, vamos a crear una propiedad a la cual evaluar:
<template>
<h4 v-if="counter > 10">Counter is greater than 10</h4>
</template>
<script>
export default {
data: function(){
return {
counter: 11
}
},
}
</script>En este ejemplo, es una propiedad entera pero, puede ser de cualquier otro tipo y como queramos evaluar los condicionales, es exactamente igual a como hacemos en vanilla JavaScript:
if(counter > 10) {
// TODO
}Para hacerlo aún más interesante, vamos a implementar un evento click:
<template>
<h4 v-if="counter > 10">Counter is greater than 10</h4>
<p>Counter is: {{ counter }}</p>
<button @click="addOne">+1</button>
</template>
<script>
export default {
data: function(){
return {
counter:0
}
},
methods: {
addOne(){
this.counter++
}
},
}
</script>Cargamos desde el componente principal que es el App.vue:
src\App.vue
<template>
<Counter/>
</template>
<script>
import Counter from './components/CounterComponent.vue'
export default {
name: 'App',
components: {
Counter
// HelloWorld
}
}
</script>Como puedes apreciar, la estructura es muy similar a la que empleamos en vanilla JavaScript:
<button onclick="addOne">+1</button>Aunque, al ser una operación sencilla que podemos realizar en una sola línea, podemos emplear el JavaScript en línea; es importante notar que usamos:
this.counterPara referenciar la variable en línea; para referenciar en el bloque de script cualquier variable, prop o método, usamos la palabra reservada this como si se tratara de una clase.
Luego, referenciamos la variable reactiva desde el template:
{{ counter }}También tenemos la cláusula del else:
<template>
<h4 v-if="counter > 10">Counter is greater than 10</h4>
<h4 v-else>Counter is less than or equal 10</h4>
<p>Counter is: {{ counter }}</p>
<button @click="addOne">+1</button>
</template>Si la condición del if es verdadera:
counter > 10Lo que va a ocurrir cuando el valor de counter sea igual o mayor a 11, veremos:
Counter is greater than 10Y si es falso:
Counter is less than or equal 10Como puedes apreciar, para emplear un componente debemos de importarlo:
import Counter from './components/CounterComponent.vue'Registrarlo a nivel del componente mediante la opción de components:
components: {
Counter
}Y luego, lo podemos emplear desde el template:
<Counter/>Volviendo al componente que creamos llamado Counter.vue, comenzamos definiendo las variables reactivas que vamos a usar en el proyecto para el contador:
counter:0Que no es más que una variable que inicializamos en cero que será el contador que vamos a emplear para sumar en una unidad al momento de que demos un click sobre el botón.
Desde el template, empleamos un evento click al presionar un botón, incrementamos en una unidad:
@click="counter++"En este ejemplo, usamos el JavaScript en línea para incrementar una propiedad definida en el bloque de data:
counter++Aunque podemos usar un enfoque más tradicional organizado en funciones:
src\components\CounterComponent.vue
<template>
<div>
{{ counter }}
<!-- <button @click="counter++">+1</button> -->
<button @click="addOne">+1</button>
</div>
</template>
<script>
export default {
data: function(){
return {
counter:0
}
},
methods: {
addOne(){
this.counter++
}
},
}
</script>Como puedes apreciar, la estructura es muy similar a la que empleamos en vanilla JavaScript:
<button onclick="addOne">+1</button>Aunque, al ser una operación sencilla que podemos realizar en una sola línea, podemos emplear el JavaScript en línea; es importante notar que usamos:
this.counterPara referenciar la variable en línea; para referenciar en el bloque de script cualquier variable, prop o método, usamos la palabra reservada this como si se tratara de una clase.
Luego, referenciamos la variable reactiva desde el template:
{{ counter }}En resumen, puedes ver un ejemplo mínimo en la cual empleamos una variable reactiva (la declarada en el bloque de data()) y al actualizarla en el bloque de script, se actualiza automáticamente en el bloque del template y esto es precisamente el concepto de la reactividad en Vue, pero, viéndolo en la práctica. Todo este comportamiento se realiza sin necesidad de hacer la operación de manera manual de referenciar un elemento mediante el ID para actualizar su valor.
En este sencillo ejemplo podemos apreciar varias características importantes de Vue, como lo son la declaración de propiedades para luego emplearlas en el template, el uso de los eventos y la reactividad de Vue que se emplea al momento de actualizar la propiedad llamada count, cuando esto ocurre, todas las partes en donde se encuentre referenciada a nivel del componente son actualizadas, como en este caso es en el template.
Incluso el evento con @ que te mostraba antes realmente es una forma corta de:
v-onQue es el que se utiliza para manejar eventos.
Otro ejemplo, el siguiente código:
<div id="app">
<h1 v-if="isActive">{{name}}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
isActive:true,
name: 'Andres'
}
})
</script>De esta forma, si cambiamos el valor de la propiedad isActive a false entonces no se mostraría el h1 definido en el HTML; para el ejemplo anterior la salida sería como la siguiente:

Pero como comentamos antes, podemos colocarle una cláusula else o mejor v-else como la siguiente para mostrar otro mensaje, bloque de código o lo que prefieras:
<div id="app">
<h1 v-if="isActive">{{name}}</h1>
<h1 v-else-if="name === 'Andres'">Hola Andres como estas</h1>
<h1 v-else="isActive">No User</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
isActive:false,
name: 'Andres'
}
})
</script>
Y hasta podemos colocar el típico v-else-if para colocar más condiciones como en el siguiente caso:
<div id="app">
<h1 v-if="isActive">{{name}}</h1>
<h1 v-else-if="name === 'Andres'">Hola Andres como estas</h1>
<h1 v-else="isActive">No User</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
isActive:false,
name: 'Andres'
}
})
</script>Figura 2-1: Ejemplo condicional
Pero podemos colocarle una cláusula else o mejor v-else como la siguiente para mostrar otro mensaje, bloque de código o lo que prefieras:
v-show
En el caso de que necesitemos que siempre se renderice el HTML (o no nos importa que se renderice) podemos emplear la directiva v-show en su lugar:
<h4 v-show="true">Vue is fantastic</h4>Como puedes apreciar, si la propiedad es TRUE, se renderiza el contenido, al igual que con los v-if:
<h4>Vue is fantastic</h4>Si es FALSE, veremos que el contenido se renderiza pero se oculta mediante la siguiente regla CSS:
<h4 style="display: none;">Vue is fantastic</h4>Con los v-show podemos también ocultar elementos; la diferencia radica en que con los v-show se oculta el elemento y no se elimina del DOM como en el caso del v-if.
Resumen
Para ocultar o mostrar elementos, contamos con dos directivas principales:
- v-if: Elimina físicamente el elemento del DOM. Es más limpio, pero si lo usas con elementos pesados, el proceso de agregar/eliminar puede generar sobrecarga.
- v-show: Simplemente aplica un estilo display: none. Es mucho más rápido para elementos que cambian de estado frecuentemente, ya que no destruye el nodo HTML.
Veamos el ejemplo final, un contador en el cual, cuando el numero es mayor a 10, entonces aparece un texto u otro:
src\components\ConditionalComponent.vue
<template>
<h4 v-if="true">Is True</h4>
<h4 v-else-if="false">Is False</h4>
<h4 v-else>Is True</h4>
<h4 v-if="counter > 10">Counter is greater than {{ counter }}</h4>
<h4 v-show="counter > 10">Counter is greater than {{ counter }}</h4>
<button @click="counter++">++</button>
<button @click="counter--">--</button>
</template>
<script>
export default {
data: function(){
return {
counter: 11
}
},
}
</script>Al igual que el uso del else-if y else.
v-for
Podemos usar la directiva v-for para iterar una lista de elementos en un array de JavaScript; su uso es muy similar al que tenemos en Vanilla JavaScript:
<template>
<ul>
<li v-for="i in items">
{{i}}
</li>
</ul>
</template>
<script>
export default {
data: function(){
return {
items: [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
]
}
},
}
</script>Si intentamos ejecutar el código anterior, veremos un error como el siguiente en la consola del navegador:
Elements in iteration expect to have 'v-bind:key'Adicional a la directiva v-for, la misma tiene que estar acompañada de una key o clave que debe ser única para cada elemento renderizado en la lista, usualmente se coloca el índice del ciclo o un dato que contenga el elemento iterable (array en este ejemplo) que estamos iterando:
<li v-for="i in items" v-bind:key="i">Y veremos el siguiente contenido renderizado en el navegador:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>Los v-for también admite un segundo argumento opcional para el índice del elemento actual:
<li v-for="(i, index) in items" v-bind:key="i">Quedando el ejercicio como:
<template>
<ul>
<li v-for="(i, index) in items" v-bind:key="i">
{{index}} - {{i}}
</li>
</ul>
</template>Y veremos el siguiente contenido renderizado en el navegador:
<ul>
<li>0 - Item 1</li>
<li>1 - Item 2</li>
<li>2 - Item 3</li>
<li>3 - Item 4</li>
</ul>- Sintaxis: Se utiliza v-for="(item, index) in lista".
- La importancia de :key: Es vital asignar un atributo :key único a cada elemento iterado. Esto permite a Vue rastrear qué elemento es cuál, garantizando una reactividad correcta y eficiente cuando eliminas o mueves elementos en el DOM.
- Métodos de array: Vue es capaz de observar mutaciones en arrays cuando usas métodos como push, splice o pop. Sin embargo, ten cuidado: algunas operaciones de asignación directa pueden no ser detectadas automáticamente si no siguen las convenciones de reactividad.
v-for con un objeto
Puedes usar el v-for para iterar a través de las propiedades de un objeto:
<ul>
<li v-for="value in object">
{{ value }}
</li>
</ul>
<script>
export default {
data: function(){
object: {
name: 'Andrew',
lastname: 'Cruz',
age: 30
},
}
}
</script>O un listado de objetos:
<template>
<ul>
<li v-for="i in items" v-bind:key="i">
{{i.title}}
</li>
</ul>
</template>
<script>
export default {
data: function(){
return {
items: [
{id: 1, title:"Entrada 1"},
{id: 2, title:"Entrada 2"},
{id: 3, title:"Entrada 3"}
]
}
},
}
</script>Vemos varias características interesante, lo primero que vemos es que definimos una lista desordenada para mostrar los elementos de array que la tenemos definida como propiedad que simula el contenido de 3 entradas; en la directiva v-for que se encuentra dentro del elemento li definimos una key que es opcional para indicar el identificador del elemento; es algo interno de Vue, lo siguiente que vemos es el renderizado básico de la propiedad posts que lo tratamos como si un array se tratase; la salida es la siguiente:

Con esta directiva podemos iterar listados; es decir, arrays:
<div v-for="c in array" v-bind:key="c.id">
<h3>{{ c.name }} {{ index }}</h3>
</div>O la forma más completa, con el índice y el elemento:
<div v-for="(c, index) in array" v-bind:key="c.id">
<h3>{{ c.name }} {{ index }}</h3>
</div>O con el array y/o basados en componentes:
<hello-world v-for="c in [1, 2, 3, 4, 5]" v-bind:key="c.id" />
<br />Con los ciclos en pocas palabras, podemos repetir múltiples veces ya sea una etiqueta HTML o un componente de Vue.
Por aquí el bloque de JavaScript:
data() {
return {
array: [
{
id: "123",
name: "andres",
},
{
id: "1234",
name: "juan",
},
],
};
},No es recomendable usar los condicionales y el ciclo v-for en una misma etiqueta HTML:
<li v-for="i in items" v-if="item.visible" v-bind:key="i.text">Si intentamos colocar la directiva v-if y v-for en un mismo elemento HTML, veremos un mensaje como el siguiente:
This 'v-if' should be moved to the wrapper elementEl cual indica que deberíamos de mover en v-if a un elemento interno del v-for:
<template>
<div>
<ul>
<template v-for="i in items" v-bind:key="i.text">
<li v-if="i.visible">{{ i.body }}</li>
</template>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ body: "Item 1", visible: true },
{ body: "Item 2", visible: false },
{ body: "Item 3", visible: true },
{ body: "Item 4", visible: false },
],
};
},
};
</script>En el ejemplo anterior usamos un elemento template con el cual podemos evitar renderizado un elemento HTML adicional, en otras palabras, el elemento template no se renderiza.
Reactividad en los arrays
Internamente Vue escucha los cambios que hagamos en las variables reactivas, cuando son números, booleanos o string la detección de cambios es directa y no tiene complicaciones, sin embargo, cuando usamos arrays debemos de emplear ciertas funciones para que Vue detecte los cambios y realice los cambios en el bloque de script y/o template.
Por ejemplo, teniendo el siguiente script:
<template>
<table >
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="(d, index) in data" :key="d.id">
<td>{{ d.id }}</td>
<td>{{ d.title }}</td>
<td>
<button @click="remove(index)">Delete</button>
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data() {
return {
data: [
{
id: 1,
title: 'Test 1'
},
{
id: 2,
title: 'Test 2'
}
],
};
},
methods: {
remove(index){
delete this.data[index]
}
},
};
</script>Veremos que los cambios no son detectados por Vue al momento de eliminar elementos del array; ya que no todas las funciones o mecanismos que existen en JavaScript para manipular los arrays son detectadas por Vue; funciones como:
- pop()
- shift()
- splice
- Asignaciones directas
- push()
Si son detectadas por Vue al momento de hacer el rastreo de variables reactivas de tipo array.
Así que, los cambios en el script anterior quedan como:
<template>
<button @click="add()">Add</button>
<table >
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="(d, index) in data" :key="d.id">
<td>{{ d.id }}</td>
<td>{{ d.title }}</td>
<td>
<button @click="remove(index)">Delete</button>
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data() {
return {
data: [
{
id: 1,
title: 'Test 1'
},
{
id: 2,
title: 'Test 2'
}
],
};
},
methods: {
add(){
this.data.push(
{
id: Date(),
title: 'Test'
}
)
/* this.data = [].concat(this.data, {
id: Date(),
title: 'Test'
}); */
/* this.data = [...this.data,
{
id: Date(),
title: 'Test'
}];*/
/* this.data[this.data.length] =
{
id: Date(),
title: 'Test'
}*/
},
remove(index){
this.data.splice(index,1)
}
},
};
</script>Y en esta oportunidad veremos que la reactividad de Vue funciona perfectamente.
Ref()
Mediante la función ref() podemos crear variables reactivas sin necesidad de definirlas en el bloque de data() esto es particularmente útil cuando empleamos el modo de composición de Vue o al momento de emplear manejadores de estados como Pinia.
Símbolo de @ para importar componentes o archivos
Como veremos más adelante, al desarrollar aplicaciones en Vue se emplea el símbolo de arroba @ como un atajo para referirse a la ruta base del proyecto; luego, se especifica la ruta al componente que se desea importar; esto es extremadamente útil cuando estamos empleando importaciones en subcarpetas.
Por ejemplo:
</script>import MyComponent from '@/components/MyComponent.vue';Comunicación entre Componentes
La arquitectura de Vue es modular, y la comunicación entre ellos es un pilar fundamental:
Comunicación Padre → Hijo (props y refs)
- props: Envían datos hacia abajo. Recuerda que son de solo lectura.
- refs: Permiten al padre obtener una referencia directa a un método o propiedad del componente hijo.
En este primer ejemplo, tenemos el componente padre que pasa datos mediante un prop hijo, con un contenido fijo:
<ChildComponent message="Andres"/>Y otro variable:
<ChildComponent :message="name"/>Es importante notar que, cuando es necesario que se evalue el atributo (propt en este ejemplo) se colocan los dos puntos (:), quedando el ejemplo como:
src\components\props\FatherComponent.vue
<template>
<ChildComponent message="Andres"/>
<hr>
<ChildComponent :message="name"/>
<ChildComponent/>
</template>
<script>
// import ChildComponent from './ChildComponent.vue';
import ChildComponent from '@/components/props/ChildComponent.vue';
export default {
components:{
ChildComponent
},
data: function(){
return {
name:'Andres'
}
},
methods: {
}
}
</script>El hijo, puede ser cualquier cosa, en este ejemplo, simplemente imprimir el propt provisto desde el padre:
src\components\props\ChildComponent.vue
<template>
<h1>Soy un hijo</h1>
<p>{{message}}</p>
</template>
<script>
export default {
data: function(){
return {
}
},
methods: {
},
// props:['message']
// props:{
// message: String
// }
props:{
message: {
type: String,
required: false,
default: 'Hola Mundo'
}
// message: {
// type: String,
// required: true
// }
}
}
</script>Cuando usas refs dentro de un bucle v-for, el resultado será un array de referencias, no un elemento único. Asegúrate de manejarlo correctamente accediendo por el índice correspondiente.
Comunicación Hijo → Padre (Eventos personalizados)
Cuando ocurre un cambio en el hijo (por ejemplo, al eliminar un ítem), este debe "avisar" al padre para que actualice la fuente de datos real.
- Emisión: Desde el hijo, disparas un evento personalizado: this.$emit('nombre-evento', datos).
- Escucha: El padre reacciona al evento: <ComponenteHijo @nombre-evento="metodoPadre" />.
Evita el "bucle infinito" al comunicar componentes. No llames a un evento del padre que, a su vez, intente disparar otro evento en el hijo si no es estrictamente necesario. Mantén la lógica de datos en el padre y la lógica de representación en el hijo siempre que sea posible.
src\components\props\events\FatherComponent.vue
<template>
<ChildComponent v-for="d in data" :key="d.id" ref="childComponent" @event-remove="remove" :item="d" />
</template>
<script>
// import ChildComponent from './ChildComponent.vue';
import ChildComponent from '@/components/props/events/ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
data: [
{
id: 1,
title: 'Test 1'
},
{
id: 2,
title: 'Test 2'
}
],
};
},
methods: {
remove(id) {
const index = this.data.findIndex(item => item.id === id);
this.$refs.childComponent[index].callFromFather(index);
this.data = this.data.filter(item => item.id !== id);
}
},
};
</script>
Fíjate que, para poder comunicarse con el componente hijo, y poder recargar el mismo al suceder algún evento en el padre, la forma predilecta es mediante una referencia:
ref="childComponent"Con esta referencia, es posible invocar métodos o propiedades desde el componente padre al hijo:
this.$refs.childComponent[index].callFromFather(index);En el hijo, implementamos este método como un método normal en los componentes en Vue:
src\components\props\events\ChildComponent.vue
<template>
<div>
<p>{{ item.id }}</p>
<p>{{ item.title }}</p>
<button @click="$emit('event-remove', item.id)">Delete</button>
<!-- <button @click="remove">Delete</button> -->
<hr>
</div>
</template>
<script>
export default {
data: function () {
return {
}
},
methods: {
// remove(){
// this.item.title = 'Eliminado'
// // this.$emit('remove', this.item.id)
// }
callFromFather(index){
console.log('Llamada desde el Padre '+index)
}
},
props: {
item: {
type: Object,
required: true,
}
}
}
</script>Redibujado de Componentes: El truco de la key
A veces, por necesidades técnicas, necesitas forzar a Vue a destruir y recrear un componente hijo desde cero. La forma más directa de lograr esto es mediante el atributo key.
- ¿Cómo funciona? Cada vez que el valor asignado a la key cambia, Vue considera que el componente es una instancia nueva y lo redibuja por completo, reiniciando su estado y ciclo de vida.
- Uso práctico: Puedes usar un timestamp (Date.now()) o un número aleatorio como valor de la key. Cuando necesites refrescar el hijo, basta con actualizar esta variable desde el padre mediante un evento click.
Este método es ineficiente para el rendimiento. Úsalo solo cuando la comunicación mediante refs o eventos ($emit) no sea suficiente.
src\components\props\events\FatherComponent.vue
<template>
<ChildComponent v-for="d in data" :key="d.id" ref="childComponent" @event-remove="remove" :item="d" />
<br>
<ChildComponent v-for="d in [{id:10, title: new Date().getTime()} ]" :key="dateKey" :item="d" />
<button @click="dateKey=new Date().getTime()">Reload By Key</button>
</template>
<script>
// import ChildComponent from './ChildComponent.vue';
import ChildComponent from '@/components/props/events/ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
dateKey: new Date().getTime(),
data: [
{
id: 1,
title: 'Test 1'
},
{
id: 2,
title: 'Test 2'
}
],
};
},
methods: {
remove(id) {
const index = this.data.findIndex(item => item.id === id);
this.$refs.childComponent[index].callFromFather(index);
this.data = this.data.filter(item => item.id !== id);
}
},
};
</script>Binding de Estilos y Clases
Además de las clases CSS, puedes vincular estilos en línea mediante objetos o arrays de forma reactiva.
- Sintaxis de objeto: v-bind:style="{ color: colorActivo, fontSize: size + 'px' }"
- Sintaxis de array: Permite combinar múltiples objetos de estilos. Si hay propiedades repetidas, la última del array sobrescribe a las anteriores (similar al funcionamiento de las hojas de estilo en cascada).
- scoped: Al añadir esta palabra a la etiqueta <style scoped>, limitas el alcance de los estilos únicamente al componente actual. Esto evita "fugas" de diseño hacia otros componentes hijos o padres.
Aquí tienes los ejemplos más comunes:
src\components\BidingStyleComponent.vue
<template>
<div>
<h2>Binding de Estilos</h2>
<!-- 1. Objeto en línea -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
Estilo con objeto en línea (Color y Tamaño)
</div>
<!-- 2. Objeto en data -->
<div :style="styleObject">
Estilo vinculado a un objeto en data
</div>
<!-- 3. Array de estilos -->
<div :style="[baseStyles, overridingStyles]">
Estilo vinculado a un array de objetos
</div>
<button @click="toggleStyles">Cambiar Estilos</button>
</div>
</template>
<script>
export default {
data() {
return {
activeColor: 'red',
fontSize: 20,
styleObject: {
color: 'blue',
fontSize: '18px',
border: '1px solid black',
padding: '10px',
marginTop: '10px'
},
baseStyles: {
backgroundColor: '#eee',
padding: '10px',
marginTop: '10px'
},
overridingStyles: {
fontWeight: 'bold',
color: 'darkgreen',
marginTop: '1000px'
}
}
},
methods: {
toggleStyles() {
this.activeColor = this.activeColor === 'red' ? 'purple' : 'red';
this.fontSize = this.fontSize === 20 ? 24 : 20;
this.styleObject.color = this.styleObject.color === 'blue' ? 'orange' : 'blue';
}
}
}
</script>Contenido Dinámico con slots
Los slots son la solución para pasar estructuras HTML complejas (como tablas, cards o layouts) hacia tus componentes hijos.
- Slot por defecto: Es el espacio sin nombre. Cualquier HTML que coloques dentro de la etiqueta del componente padre terminará ahí.
- Slots con nombre: Permiten insertar contenido en secciones específicas del hijo (ej. <template #header>...</template>).
- Ventaja: Te permite mantener una estructura fija en el hijo (estilos, animaciones) mientras personalizas el contenido desde el padre de forma limpia y reutilizable.
En el componente hijo definimos los slots, ya sea por defecto o con nombre, recuerda que solamente puede haber un solo slog por defecto, que es el que NO tiene nombre:
src\components\slot\SlotChild.vue
<template>
<div class="slot-child">
<h3>Componente Hijo (Define los Slots)</h3>
<div class="header-area">
<!-- Slot con nombre -->
<slot name="header">
<p>Contenido por defecto del Header</p>
</slot>
</div>
<div class="content-area">
<!-- Slot por defecto -->
<slot>
<p>Contenido por defecto del Body</p>
</slot>
</div>
</div>
</template>
<style scoped>
.slot-child {
border: 2px dashed #ccc;
padding: 15px;
margin: 10px 0;
}
.header-area {
background-color: #f4f4f4;
padding: 5px;
margin-bottom: 10px;
}
</style>Desde el padre, usamos los slots:
src\components\slot\SlotComponent.vue
<template>
<div>
<h2>Ejemplo de Slots (Padre)</h2>
<div class="header-area">
<!-- Slot con nombre -->
<p>Contenido por defecto del Header</p>
</div>
<hr>
<SlotChild>
<!-- Usando slot con nombre 'header' -->
<template v-slot:header>
<h4>Título personalizado desde el Padre</h4>
</template>
<!-- Contenido para el slot por defecto -->
<p>Este párrafo se inyecta en el slot principal del hijo.</p>
<button>Acción inyectada</button>
</SlotChild>
</div>
</template>
<script>
import SlotChild from './SlotChild.vue';
export default {
components: {
SlotChild
}
}
</script>️ Observadores (watch)
Los watchers son ideales para ejecutar lógica personalizada cuando una propiedad cambia de valor.
- Sintaxis: Se definen dentro del bloque watch. Cada función debe llevar el nombre de la propiedad que desea observar y recibe dos argumentos: (newValue, oldValue).
- Caso de uso: Son perfectos para ejecutar efectos secundarios, como realizar una petición a una API cuando un filtro cambia o sincronizar datos entre componentes.
En el siguiente ejemplo, verás que, al presionar el botón, cuya propiedad se esta observando, se imprime un mensaje por la consola del navegador:
src\components\WatchComponent.vue
<template>
<div class="watch-container">
<h2>Ejemplo de Watch</h2>
<p>Cuenta actual: {{ count }}</p>
<button @click="count++">Incrementar</button>
<p><strong>Log:</strong> {{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
count: 0,
message: 'Esperando cambios...'
}
},
watch: {
count(newValue, oldValue) {
this.message = `El valor cambió de ${oldValue} a ${newValue}`;
}
}
}
</script>Inyección de HTML: v-html
Si necesitas renderizar contenido HTML crudo (ej. desde un CMS), usa la directiva v-html="contenido".
src\components\HTMLComponent.vue
<template>
<div>
<h3>Imprimir HTML (v-html)</h3>
<!-- La directiva v-html interpreta el string como HTML real -->
{{ htmlContent }}
<div v-html="htmlContent"></div>
</div>
</template>
<script>
export default {
data() {
return {
htmlContent: '<p style="color: blue; font-weight: bold;">Este es un texto renderizado dinámicamente con etiquetas HTML.</p>'
}
}
}
</script>Solo usa esta directiva con contenido confiable, ya que inyectar HTML sin filtrar es una puerta abierta a ataques de tipo XSS (Cross-Site Scripting).
¿Options API o Composition API?
Hemos estado trabajando con Options API, que organiza el código en bloques (data, methods, computed, watch). Sin embargo, existe Composition API (el estándar moderno desde Vue 3):
- Diferencia clave: En Composition API, la lógica se agrupa por funcionalidad en lugar de por opciones. Es más limpio, más corto y permite una reutilización de código superior.
- Recomendación: Aunque Options API es excelente para comenzar y entender la reactividad, te recomiendo familiarizarte con Composition API a medida que ganes experiencia. Es el futuro del ecosistema Vue y la documentación oficial se inclina cada vez más hacia esta sintaxis.
Aquí tienes un ejemplo de Composition API y lo puedes comparar con el biding de estilos que hicimos antes usando el option API:
BidingStyleComponent.vue
<template>
<div>
<h2>Binding de Estilos</h2>
<!-- 1. Objeto en línea -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
Estilo con objeto en línea (Color y Tamaño)
</div>
<!-- 2. Objeto en data -->
<div :style="styleObject">
Estilo vinculado a un objeto en data
</div>
<!-- 3. Array de estilos -->
<div :style="[baseStyles, overridingStyles]">
Estilo vinculado a un array de objetos
</div>
<button @click="toggleStyles">Cambiar Estilos</button>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue';
const activeColor = ref('red');
const fontSize = ref(20);
const styleObject = reactive({
color: 'blue',
fontSize: '18px',
border: '1px solid black',
padding: '10px',
marginTop: '10px'
});
const baseStyles = reactive({
backgroundColor: '#eee',
padding: '10px',
marginTop: '10px'
});
const overridingStyles = reactive({
fontWeight: 'bold',
color: 'darkgreen',
marginTop: '1000px'
});
const toggleStyles = () => {
activeColor.value = activeColor.value === 'red' ? 'purple' : 'red';
fontSize.value = fontSize.value === 20 ? 24 : 20;
styleObject.color = styleObject.color === 'blue' ? 'orange' : 'blue';
};
</script>Opciones principales en el bloque se template
En este apartado, veremos las opciones más comunes que podemos realizar en los bloques de template, como el uso de directivas como los condicionales, for, impresiones e importaciones.
Impresiones
Como comentamos anteriormente, para imprimir alguna primitiva como texto, número o boolean empleamos las dobles llaves:
{{var}}V-model
Como comentamos antes, los v-model en Vue son una directiva que permite crear un enlace bidireccional entre un valor de cualquier etiqueta HTML de un formulario como un SELECT, INPUT, TEXTAREA o similares.
El uso de v-model es la forma más eficiente de crear una conexión Full Duplex (bidireccional) entre el script y el template.
¿Cómo funciona? Todo lo que el usuario escribe en un campo de formulario (input, textarea, select) se sincroniza automáticamente con una variable en tu bloque data.
- Sintaxis: Se utiliza v-model="nombreVariable".
- Reactividad: Cualquier cambio en la variable desde el script se refleja instantáneamente en el HTML, y viceversa.
Si en el template, colocamos un v-model con el cual podemos referenciar crear una vinculación bidireccional entre los datos y un campo de formulario (TEXTAREA, INPUTS, SELECT, RADIUS... en pocas palabras, podemos usar los v-model en todos los tipos de campos de formularios) como un input de tipo texto:
<template>
<label>Name</label>
<input type="text" v-model="name">
<label>Sex</label>
<select type="text" v-model="sex">
<option value="M">Male</option>
<option value="F">Female</option>
</select>
<label>About</label>
<textarea v-model="about"></textarea>
</template>
Y una variable reactiva en Vue:
<script>
export default {
data() {
return {
name:'',
sex:'',
about:''
}
},
}
</script>Vue monitorea el elemento del campo de formulario y lo vincula con la variable reactiva y actualiza la variable cuando hay un cambio en el elemento de formulario vinculado y viceversa; puedes probar ejecutar el siguiente ejercicio:
<template>
<label>Name</label>
<input type="text" v-model="name">
<label>Sex</label>
<select type="text" v-model="sex">
<option value="M">Male</option>
<option value="F">Female</option>
</select>
<label>About</label>
<textarea v-model="about"></textarea>
<button @click="send">Send</button>
</template>
<script>
export default {
data() {
return {
name:'',
sex:'',
about:''
}
},
methods: {
send(){
alert(`
name ${this.name}
sex ${this.sex}
about ${this.about}
`)
}
},
}
</script>Y verás que, al establecer los datos en el v-model, se actualizan automáticamente en las variables reactivas; aunque, también podemos establecer valores desde el bloque de script, por ejemplo, para restablecer el formulario:
<template>
<label>Name</label>
<input type="text" v-model="name">
<label>Sex</label>
<select type="text" v-model="sex">
<option value="M">Male</option>
<option value="F">Female</option>
</select>
<label>About</label>
<textarea v-model="about"></textarea>
<button @click="send">Send</button>
<button @click="reset">Reset</button>
</template>
<script>
export default {
data() {
return {
name:'',
sex:'',
about:''
}
},
methods: {
send(){
alert(`
name ${this.name}
sex ${this.sex}
about ${this.about}
`)
},
reset(){
this.name=''
this.sex='M'
this.about=''
}
},
}
</script>Gestión de Formularios y el modificador .prevent
Cuando trabajamos con etiquetas <form>, el comportamiento por defecto de HTML es recargar la página al enviar los datos. Esto es contraproducente en una SPA.
El problema de la recarga
Si el navegador recarga, perdemos todo el estado en memoria de nuestra aplicación.
Empleando el atributo @submit.prevent el cual es realmente un escuchador del evento submit del formulario, capturamos el evento y es procesado mediante el método mySubmit():
src\components\FormComponent.vue
<template>
<form @submit.prevent="send">
<input type="text" v-model="name">
<!-- <button @click="send">Send</button> -->
<button>Send</button>
</form>
</template>
<script>
export default {
data: function () {
return {
name: ''
}
},
methods: {
send() {
console.log(this.name);
}
}
}
</script>En Vue, el formulario es más una convención visual. No necesitas definir action ni method en el HTML, ya que la comunicación con tu API (usando fetch o axios) la gestionarás directamente desde tus métodos en Vue.
Vas a ver las estas directivas en Vue comienza con v- seguido de un guion y esto es una organización interna del framework para especificar que estas directivas/atributos son de Vue.
Eventos
Los eventos son el mecanismo que tenemos para que el usuario pueda interactuar con la aplicación, los eventos en Vue, son los mismos que tenemos disponibles en vanilla JavaScript como lo son el evento click y de teclados; además de esto, tenemos muchas opciones para por ejemplo escuchar la tecla enter, ejecutar el evento una sola vez, entre otras.
Usamos la directiva v-on para escuchar los eventos del DOM que ocurren en JavaScript o la forma recortada (shortcut) @.
Para usar los eventos, debemos de usar el siguiente atributo:
v-onSeguido del evento que queremos usar, por ejemplo, el click:
v-on:clickEl shortcut al v-on viene siendo el carácter del arroba:
@Así que, si queremos emplear el evento click queda como:
@click
Para definir el cuerpo del evento, tenemos dos formas:
En línea: Este es el formato más sencillo que tenemos disponible, consiste en que podemos indicar la operación a realizar directamente en el atributo @click, es decir, como parte del valor:
const count = ref(0)template
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>Mediante métodos: Esta es un esquema similar al empleado en vanilla JavaScript, que consiste que mediante el atributo de @click especificamos un método el cual se va a invocar al momento de ocurrir el evento click.
const name = ref('Vue.js')
function hello() {
alert(`Hello ${name.value}!`)
}template
<button @click="hello">Hello</button>Otros eventos que podemos usar son, el de teclado:
<input type="text" @keyup="submit" />Capturar la tecla enter:
<input type="text" @keyup.enter="submit" />Alias Key
Aparte de escuchar la tecla enter, Vue proporciona alias para las claves más utilizadas:
- .enter
- .tab
- .delete (captura las teclas "Eliminar" y "Retroceso")
- .esc
- .space
- .up
- .down
- .left
- .right
Teclas modificadoras del sistema
En Vue, también tenemos acceso a otras teclas conocidas como modificadores para activar detectores de eventos del mouse o del teclado solo cuando se presiona la tecla modificadora correspondiente:
- .ctrl
- .alt
- .shift
- .meta
Por ejemplo:
<input type="button" @keyup.ctrl="toDo" />Eventos personalizados
También podemos crear eventos personalizados en Vue, los cuales son muy útiles para comunicar componentes hijos con el padre; para eso, en el componente padre, definimos el evento al momento de cargar el hijo:
<template>
<div>
<h1>{{ title }}</h1>
<ChildComponent @event-in-child="callback" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent,
},
methods: {
callback(){
console.log('Custom event')
}
},
};
</script>Desde el componente hijo, puedes emitir eventos personalizados usando el método $emit:
<template>
<button @click="$emit('eventInChild')">Click this button</button>
</template>Puedes pasar parámetros mediante el evento:
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent,
},
methods: {
callback(p1){
console.log('Custom event '+p1)
}
},
};
</script>Y en el hijo:
<template>
<button @click="$emit('eventInChild', 'param')">Click this button</button>
</template>Puedes pasar los parámetros que sean necesarios separándolos por comas:
<template>
<button @click="$emit('eventInChild', 'param', n1, *** , nx)">Click this button</button>
</template>Los eventos personalizados son muy útiles para pasar datos o estados desde el componente hijo al padre, al ser la comunicación inversa (ya que es el componente padre el que carga al hijo).
Opciones principales en el bloque de style
Como función importante que tenemos disponible en el bloque de style, cuyo propósito es definir el estilo o CSS para el componente es, si quieres que el estilo sea global a la aplicación:
<style>
button{
background: green;
}
</style>O local al componente:
<style scoped>
button{
background: green;
}
</style>Raw o renderizar HTML en Vue
Muchas veces tenemos en una propiedad o función un contenido HTML que queremos renderizar directamente en el template; si lo hacemos de la manera corriente con las llaves llaves {{}} no se va a obtener el resultado deseado, tenemos que emplear la directiva v-html en su lugar e indicarle la propiedad o función.
<!-- **RAW HTML -->
<p>
{{ rawhtml }}
</p>
<p v-html="rawhtml"></p>
<!-- **RAW HTML FIN-->Y en el JavaScript
rawhtml: "<span style='color:red'>Hola texto rojo</span>",Puedes consultar el repo para más información.
Alias para las importaciones en Vue
En Vue, para evitar tener sintaxis como la siguiente al momento de ir cargando componentes aparte desde distintas ubicaciones de tu proyecto:
import Base from "../../components/Base" La cual se complica más, dependiendo de donde importamos; por ejemplo si estamos en ubicaciones más internas y tenemos que navegar a archivos superiores; tenemos que seguir con esta navegación.
En vez de usar este tipo de sintaxis, podemos usar un alias, en cual apunta directamente a la carpeta source (src) de nuestro proyecto; por lo tanto, sin importar de donde se encuentren nuestros elementos, siempre tenemos un acceso directo a nuestra carpeta src; con esto nuestras importaciones quedan muchas más concisas, legibles y directas; para esto, tenemos que usar el arroba @:
import Base from "@/components/Base"Estilos locales y globales a los componentes scoped Vue
En Vue, podemos aplicar reglas de estilos de manera global, para toda la aplicación o que solamente aplique en un único componente.
Vue es un marco que fue creado para aplicaciones modulares, es el nuevo esquema que no es tan nuevo, pero que poco a poco va evolucionando bajo un mismo lineamiento en el cual requerimos que todo sea perfectamente modular e integrable con otros módulos o submódulos; en vue a estos módulos se les llaman componentes en los cuales tenemos unas minis aplicaciones que hacen una tarea en particular; recordemos que, siguiente la estructura de una aplicación en Vue, en un componente, tenemos:
- template
- script
- css
Esto es un componente, en cuando al template y el script sabemos que fácilmente corresponde o vive en el mismo componente, pero el estilo al tratar con hojas de estilos en cascadas, CSS la cosa cambia un poco, ya que una de las características que tenemos en este lenguaje, es que es global a TODA la app, y a la final no importa cuantos desestructura tu app en componentes, que a la final va a ser UNA sola aplicación ejecutándose en un navegador; por lo tanto el CSS que coloques a la final en cada componente, se va a regar al resto cuando ejecutes tu app!
Suponte el siguiente esquema; tenemos en nuestro App.vue un template que carga dos componentes:
En el App.vue:
<template>
<mi-primer-componente/>
<hello-world/>
</template>
<script>
import MiPrimerComponente from ',/components/MiPrimerComponente'
import HelloWorld from './components/HelloWorld'
export default {
components: {
MiPrimerComponente,
HelloWorld
},
}
</script>El uso de componentes lo vemos más claramente en la entrada en la cual creamos una app en Vue tipo CRUD que consume una Rest API.
Componente 1: Hello World
Tiene un H1 al cual quiero colocar un color de azul
<template>
<h1>C1<h1/>
</template>
<style scoped>
h1 {
color: blue
}
</style>Componente 2: Mi Primer Componente
Tiene un H1 al cual quiero colocar un color de rojo
<template>
<h1>C2<h1/>
</template>
<style scoped>
h1 {
color: red;
}
</style>Cuando renderizas tu app, tienes el siguiente resultado:

Solamente te va a aparecer un solo color, que puede que sea rojo o puede que sea azul, pero NO es lo que especificamos, ya que queríamos un color para el H1 diferente por cada componente.
Definiendo el scope de estilos
Como indicamos, al tener componentes, es probable que no quieres que choquen tus estilos, por ejemplo puedes que tengas un componente de listado en el cual le das estilo a un div para que muestre un item, pero este elemento div, puedes que lo uses para el banner, footer, barra lateral y si no hacemos algo, chocaran estos estilos de una manera espantosa!
Para indicar que queremos que cada estilo se quede en su componente, tenemos el atributo scope, que le definimos a las hojas de estilo, por lo tanto, para nuestros componentes, si queremos que el estilo que definen sea local al mismo y NO extienda como una "Cascada" a otros componentes hermanos, hijos o padres...:
<style scoped>
h1 {
color: red;
}
</style>Tienes que colocar scoped para cada estilo que quieres que sea local a ese componente
Ya con esto, tenemos el resultado esperado:

Vue devtools: Debug a tus apps
Las Vue devtoools son unas herramientas fantásticas que nos permiten hacer debugs fácilmente a nuestras aplicaciones en Vue; la razón de esto, es que cuando creamos una app en Vue, en base componentes, todo a la final termina en un solo archivo y si una pieza o componente falla o queremos hacerle un seguimiento y hacemos debug a dicha aplicación con las herramientas que ya conocemos:
Como puedes ver, no vemos nada relacionado a nuestra app en componentes; para poder hacer un debug como dios manda y poder ver componentes y propiedades, tenemos que instalar las devtools que lo tenemos en la mayoría de los navegadores modernos como Firefox o Google Chrome; en el caso de Google Chrome:
https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd
Con esto, tenemos un nueva nueva pestaña en nuestra consola de desarrolladores.
En la cual como puedes ver, vemos la app como realmente es. Esta extensión es ideal para poder seguir esta guía.