Directivas Personalizadas
Introducción
Además del conjunto predeterminado de directivas que vienen en el core (como v-model o v-show), Vue también te permite registrar tus propias directivas personalizadas.
Hemos introducido dos formas de reutilización de código en Vue: componentes y composables. Los componentes son los bloques de construcción principales, mientras que los composables se centran en la reutilización de lógica con estado. Las directivas personalizadas, por otro lado, están principalmente destinadas a reutilizar lógica que involucra acceso de bajo nivel al DOM en elementos simples.
Una directiva personalizada se define como un objeto que contiene hooks de ciclo de vida similares a los de un componente. Los hooks reciben el elemento al que está vinculada la directiva. Aquí hay un ejemplo de una directiva que añade una clase a un elemento cuando Vue lo inserta en el DOM:
vue
<script setup>
// habilita v-highlight en el template
const vHighlight = {
mounted: (el) => {
el.classList.add('is-highlight')
}
}
</script>
<template>
<p v-highlight>¡Esta oración es importante!</p>
</template>¡Esta oración es importante!
En <script setup>, cualquier variable camelCase que comience con el prefijo v puede usarse como una directiva personalizada. En el ejemplo anterior, vHighlight puede usarse en el template como v-highlight.
Si no estás usando <script setup>, las directivas personalizadas pueden registrarse usando la opción directives:
js
export default {
setup() {
/*...*/
},
directives: {
// habilita v-highlight en el template
highlight: {
/* ... */
}
}
}También es común registrar globalmente directivas personalizadas a nivel de la aplicación:
js
const app = createApp({})
// hacer que v-highlight sea utilizable en todos los componentes
app.directive('highlight', {
/* ... */
})Es posible tipar directivas personalizadas globales extendiendo la interfaz ComponentCustomProperties de vue
Más detalles: Tipado de Directivas Globales Personalizadas
Cuándo usar directivas personalizadas
Las directivas personalizadas solo deben usarse cuando la funcionalidad deseada solo se puede lograr mediante manipulación directa del DOM.
Un ejemplo común de esto es una directiva personalizada v-focus que pone un elemento en foco.
vue
<script setup>
// habilita v-focus en el template
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>Esta directiva es más útil que el atributo autofocus porque funciona no solo al cargar la página, ¡también funciona cuando el elemento es insertado dinámicamente por Vue!
La creación de templates declarativas con directivas incorporadas como v-bind se recomienda cuando sea posible porque son más eficientes y compatibles con el renderizado en el servidor.
Hooks de Directiva
Un objeto de definición de directiva puede proporcionar varias funciones de hook (todas opcionales):
js
const myDirective = {
// llamado antes de aplicar los atributos del
// elemento vinculado o los escuchadores de eventos
created(el, binding, vnode) {
// ver más abajo para detalles sobre los argumentos
},
// llamado justo antes de insertar el elemento en el DOM.
beforeMount(el, binding, vnode) {},
// llamado cuando el componente padre del elemento
// vinculado y todos sus hijos están montados.
mounted(el, binding, vnode) {},
// llamado antes de actualizar el componente padre
beforeUpdate(el, binding, vnode, prevVnode) {},
// llamado después de que el componente padre y
// todos sus hijos se hayan actualizado
updated(el, binding, vnode, prevVnode) {},
// llamado antes de desmontar el componente padre
beforeUnmount(el, binding, vnode) {},
// llamado cuando se desmonta el componente padre
unmounted(el, binding, vnode) {}
}Argumentos de los Hooks
Los hooks de directiva reciben estos argumentos:
el: el elemento al que está vinculada la directiva. Esto se puede usar para manipular directamente el DOM.binding: un objeto que contiene las siguientes propiedades.value: El valor pasado a la directiva. Por ejemplo, env-my-directive="1 + 1", el value sería2.oldValue: El valor anterior, solo disponible enbeforeUpdateyupdated. Está disponible independientemente de si el valor ha cambiado o no.arg: El argumento pasado a la directiva, si existe. Por ejemplo, env-my-directive:foo, el arg sería"foo".modifiers: Un objeto que contiene modificadores, si existen. Por ejemplo, env-my-directive.foo.bar, el objeto modifiers sería{ foo: true, bar: true }.instance: La instancia del componente donde se usa la directiva.dir: el objeto de definición de la directiva.
vnode: el VNode subyacente que representa el elemento vinculado.prevVnode: el VNode que representa el elemento vinculado del renderizado anterior. Solo disponible en los hooksbeforeUpdateyupdated.
Como ejemplo, considera el siguiente uso de directiva:
template
<div v-example:foo.bar="baz">El argumento binding sería un objeto con la forma de:
js
{
arg: 'foo',
modifiers: { bar: true },
value: /* valor de `baz` */,
oldValue: /* valor de `baz` de la actualización anterior */
}Similar a las directivas incorporadas, los argumentos de las directivas personalizadas pueden ser dinámicos. Por ejemplo:
template
<div v-example:[arg]="value"></div>Aquí el argumento de la directiva se actualizará reactivamente basándose en la propiedad arg en el estado de nuestro componente.
Nota
Aparte de el, debes tratar estos argumentos como de solo lectura y nunca modificarlos. Si necesitas compartir información entre hooks, se recomienda hacerlo a través del dataset del elemento.
Abreviación de Función
Es común que una directiva personalizada tenga el mismo comportamiento para mounted y updated, sin necesidad de los otros hooks. En tales casos podemos definir la directiva como una función:
template
<div v-color="color"></div>js
app.directive('color', (el, binding) => {
// se llamará tanto para `mounted` como para `updated`
el.style.color = binding.value
})Literales de Objeto
Si tu directiva necesita múltiples valores, también puedes pasar un literal de objeto JavaScript. Recuerda, las directivas pueden tomar cualquier expresión JavaScript válida.
template
<div v-demo="{ color: 'white', text: '¡hola!' }"></div>js
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "¡hola!"
})Uso en Componentes
No recomendado
No se recomienda usar directivas personalizadas en componentes. Puede ocurrir un comportamiento inesperado cuando un componente tiene múltiples nodos raíz.
Cuando se usan en componentes, las directivas personalizadas siempre se aplicarán al nodo raíz de un componente, de forma similar a los Atributos de Fallthrough.
template
<MyComponent v-demo="test" />template
<!-- template de MyComponent -->
<div> <!-- aquí se aplicará la directiva v-demo -->
<span>Contenido de mi componente</span>
</div>Ten en cuenta que los componentes pueden tener potencialmente más de un nodo raíz. Cuando se aplica a un componente multi-raíz, una directiva será ignorada y se emitirá una advertencia. A diferencia de los atributos, las directivas no pueden pasarse a un elemento diferente con v-bind="$attrs".