Directivas en Vue 3: guía completa para entenderlas bien
Las directivas en Vue son atributos especiales que permiten aplicar lógica reactiva directamente sobre el DOM.
Todas comienzan con v- y existen para reducir código imperativo y hacer que el template sea más expresivo y declarativo.
Esta entrada es un mapa general: no profundiza al extremo, pero te deja claro qué hace cada directiva, cuándo usarla y qué problema resuelve. Cada una tendrá luego su artículo dedicado.
v-if, v-else-if, v-else
Sirven para renderizar o eliminar elementos del DOM según una condición reactiva. Si la condición es falsa, el elemento no existe en el DOM.
Úsala cuando:
- El contenido es pesado
- No siempre debe existir
- Depende de permisos o estados críticos
<script setup>
import { ref } from 'vue'
const isLogged = ref(true)
</script>
<template>
<p v-if="isLogged">Bienvenido</p>
<p v-else>No has iniciado sesión</p>
</template><script>
export default {
data() {
return {
isLogged: true
}
}
}
</script>
<template>
<p v-if="isLogged">Bienvenido</p>
<p v-else>No has iniciado sesión</p>
</template>Si quieres conocer más lee la guía de Directivas en Vue: v-if, v-else y v-show.
v-show
Controla la visibilidad usando CSS (display: none), pero el elemento siempre existe en el DOM.
Úsala cuando:
- El elemento se muestra y oculta con frecuencia
- No quieres pagar el costo de montar y desmontar el nodo
<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>
<template>
<p v-show="isVisible">Contenido visible</p>
</template><script>
export default {
data() {
return {
isVisible: true
}
}
}
</script>
<template>
<p v-show="isVisible">Contenido visible</p>
</template>Si quieres conocer más lee la guía de Directivas en Vue: v-if, v-else y v-show.
v-for
Permite renderizar listas a partir de arreglos u objetos reactivos.
Clave mental:
v-fordescribe estructura, no lógica.
<script setup>
import { ref } from 'vue'
const items = ref([
{ id: 1, name: 'Vue' },
{ id: 2, name: 'React' }
])
</script>
<template>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</template><script>
export default {
data() {
return {
items: [
{ id: 1, name: 'Vue' },
{ id: 2, name: 'React' }
]
}
}
}
</script>
<template>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</template>key no es opcional. Nunca lo fue.
Es esencial para que Vue pueda optimizar correctamente el renderizado.
Si quieres conocer más lee la guía de Directivas en Vue: v-for.
v-bind
Vincula dinámicamente atributos HTML o props de componentes.
Piensa en v-bind como:
“Este atributo depende del estado”
<script setup>
import { ref } from 'vue'
const imageUrl = ref('https://example.com/image.jpg')
</script>
<template>
<img v-bind:src="imageUrl" alt="Imagen dinámica" />
</template><script>
export default {
data() {
return {
imageUrl: '/logo.png',
description: 'Logo'
}
}
}
</script>
<template>
<img :src="imageUrl" :alt="description" />
</template>Si quieres conocer más lee la guía de Directivas en Vue: v-bind.
v-model
Crea una sincronización bidireccional entre el estado y un input o componente.
Es ideal para:
- Formularios
- Inputs controlados
- Componentes reutilizables
<script setup>
import { ref } from 'vue'
const username = ref('')
</script>
<template>
<input v-model="username" placeholder="Ingresa tu nombre de usuario" />
<p>Hola, {{ username }}!</p>
</template><script>
export default {
data() {
return {
username: ''
}
}
}
</script>
<template>
<input v-model="username" placeholder="Ingresa tu nombre de usuario" />
<p>Hola, {{ username }}!</p>
</template>Internamente, combina props y eventos (modelValue + update:modelValue).
No es magia, pero se le parece bastante.
Si quieres conocer más lee la guía de Directivas en Vue: v-model.
v-on
Escucha eventos del DOM y ejecuta lógica reactiva.
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => {
count.value++
}
</script>
<template>
<button v-on:click="increment">Has hecho clic {{ count }} veces</button>
</template><script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
}
}
</script>
<template>
<button v-on:click="increment">Clickeame</button>
<p>Has clickeado {{ count }} veces.</p>
</template>Soporta modificadores (.stop, .prevent, .once, etc.) que evitan código innecesario.
Si quieres conocer más lee la guía de Directivas en Vue: v-on.
v-text
Inserta texto plano en un elemento, reemplazando su contenido.
<script setup>
import { ref } from 'vue'
const message = ref('Hola Mundo')
</script>
<template>
<div v-text="message"></div>
</template><script>
export default {
data() {
return {
message: 'Hola Vue'
}
}
}
</script>
<template>
<div v-text="message"></div>
</template>No se usa mucho, pero existe para casos muy específicos donde no quieres interpolaciones.
Si quieres conocer más lee la guía de Directivas en Vue: v-text y v-html.
v-html
Inserta HTML sin escapar.
<script setup>
import { ref } from 'vue'
const rawHtml = ref('<strong>Texto en negrita</strong>')
</script>
<template>
<div v-html="rawHtml"></div>
</template><script>
export default {
data() {
return {
rawHtml: '<strong>HTML dinámico</strong>'
}
}
}
</script>
<template>
<div v-html="rawHtml"></div>
</template>⚠️ Nunca lo uses con contenido no confiable. Es una puerta directa a XSS si no sabes exactamente lo que estás renderizando.
Si quieres conocer más lee la guía de Directivas en Vue: v-text y v-html.
v-slot
Permite definir contenido dinámico dentro de componentes mediante slots.
<script setup>
</script>
<template>
<MyCard>
<template v-slot:header>
<h1>Encabezado Personalizado</h1>
</template>
<p>Contenido del cuerpo de la tarjeta.</p>
<template v-slot:footer>
<button>Acción</button>
</template>
</MyCard>
</template><script>
export default {
components: { MyCard }
}
</script>
<template>
<MyCard>
<template v-slot:header>
<h1>Encabezado Personalizado</h1>
</template>
<p>Contenido del cuerpo de la tarjeta.</p>
<template v-slot:footer>
<button>Acción</button>
</template>
</MyCard>
</template>Es clave para crear componentes flexibles, composables y reutilizables.
Si quieres conocer más lee la guía de Directivas en Vue: v-slot.
v-once
Renderiza el contenido una sola vez y lo excluye del sistema reactivo.
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p v-once>Este texto no cambiará: {{ count }}</p>
<button @click="count++">Incrementar</button>
</template><script>
export default {
data() {
return {
count: 0
}
}
}
</script>
<template>
<p v-once>Este texto no cambiará: {{ count }}</p>
<button @click="count++">Incrementar</button>
</template>Útil cuando el contenido no debe actualizarse jamás, incluso si el estado cambia.
Si quieres conocer más lee la guía de Directivas en Vue: v-once / v-memo / v-pre.
v-memo
Evita renderizados innecesarios cuando las dependencias no cambian.
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<div v-memo="[count]">
<p>Este bloque solo se re-renderiza si 'count' cambia: {{ count }}</p>
</div>
<button @click="count++">Incrementar</button>
</template><script>
export default {
data() {
return {
value: 10
}
}
}
</script>
<template>
<div v-memo="[value]">
<p>El valor es: {{ value }}</p>
</div>
</template>Es una optimización avanzada. No está pensada para usarse “porque sí”, sino en cuellos de botella reales.
Si quieres conocer más lee la guía de Directivas en Vue: v-once / v-memo / v-pre.
v-pre
Evita que Vue compile el contenido del nodo.
<script setup>
</script>
<template>
<div v-pre>
{{ esto_no_se_evaluará }}
</div>
</template><script>
export default {}
</script>
<template>
<div v-pre>
{{ esto_no_se_evaluará }}
</div>
</template>Perfecta para mostrar snippets, ejemplos literales o templates de demostración.
Si quieres conocer más lee la guía de Directivas en Vue: v-once / v-memo / v-pre.
v-cloak
Oculta el template hasta que Vue termine de montar la aplicación.
<script setup>
</script>
<template>
<div v-cloak>
{{ mensaje }}
</div>
</template><script>
export default {}
</script>
<template>
<div v-cloak>
{{ mensaje }}
</div>
</template>Evita el parpadeo inicial en aplicaciones renderizadas del lado del cliente.
Si quieres conocer más lee la guía de Directivas en Vue: v-cloak.
Directivas personalizadas
Permiten extender Vue para manipular directamente el DOM cuando no hay otra opción más declarativa.
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.directive('focus', {
mounted(el) {
el.focus()
}
})<template>
<input v-focus />
</template>Son poderosas, pero deben usarse con cuidado: si abusas de ellas, probablemente estás rompiendo el modelo mental de Vue.
Si quieres conocer más lee la guía de Directivas en Vue: Directivas personalizadas.
Conclusión
Las directivas no son solo sintaxis bonita. Son contratos claros entre el estado y el DOM.
Este artículo es el punto de partida. Cada directiva tendrá su entrada individual, con:
- Casos reales
- Errores comunes
- Buenas y malas prácticas
Este mapa ya te permite leer código Vue con criterio. Lo demás es profundidad, no confusión.
