Introducción ¿qué son las directivas?

Las directivas son unos atributos que puedes añadir en el HTML de los componentes que permiten controlar el elemento DOM sobre el que se colocan.

Si ya has usando Vue estoy seguro ya hayas usado directivas, aunque no lo sabías. Cuando usas el v-model y el v-show realmente lo que estás usando son directivas, auque estas vienen ya creadas con Vue.

Como dentro de una directiva tienes acceso al elemento DOM sobre el que se aplica, las posibilidades son casi infinitas. Puedes ejecutar código javascript directamente al elemento del DOM y además puedes personalizar cada directiva porque admiten el paso de parámetros.

En el artículo anterior (Cómo se usan los filters de Vue) hablamos de los filters y de cómo se usan insertándolos en los datos de la vista, pero las directivas son totalmente distintas, auque también se usan dentro de la vista de los componentes, las directivas se ponen como atributo del HTML y no dentro de los datos que se pintan. Ahora veremos esto con más detalle.

¿Cómo se crean las directivas?

Lo primero que tienes que saber, es que las directivas siempre se usan poniendo dentro de la etiqueta HTML v- seguido del nombre de la directiva.

Primero vamos a crear la directiva más básica, una que no recibe nada ni hace nada. Yo lo que suelo hacer es crear un fichero llamado direcives.js para tener todas las directivas localizadas, ya que no aconstumbro a tener muchas.

Por ejemplo, vamos a crear la directiva esta que no hace nada, la voy a llamar void:

// src/directives.js

import Vue from 'vue'

Vue.directive('void', function(el) {
  console.log("Directiva");
})

Para usar este fichero de directivas lo tienes que importar en el main.js:

// /src/main.js

import Vue from 'vue'
import App from './App'
import "./filters"

new Vue({
  el: '#app',
  template: '<App/>',
  components: { App },
})

Para usar esta directiva que hemos creado tan solo tienes que poner dentro de la etiqueta HTML del componente:

<template>
  <div class="component">
    <div v-void></div>
  </div>
</template>

Recuerda que siempre tienes que poner delante del nombre de la directiva el v-.

Como ves, la directiva es una función que recibe un parámetro el. Este parámetro es el elemento DOM sobre el que se apica la directiva.

Hooks de las directivas

Las directivas tienen sus propios hooks, es decir, tienen una serie de funciones para controlar su ciclo de vida, veamos cuáles son:

  • bind: Se ejecuta en el momento en el que la directiva se añade al elemento del DOM. Sería como el created() de los componentes
  • inserted: Cuando se ha insertado en el DOM el elemento sobre el que se aplica esta directiva. Como el mounted() de los componentes.
  • updated: Cuando cambia el elemento del DOM sobre el que está aplicada la directiva.
  • componentUpdated: Cuando todo el componente y el hijo han terminado de ser actualizados.
  • unbind: Cuando la directiva es eliminada de ese elemento del DOM.

En el anterior ejemplo la directiva era una función. Para usar los hooks es necesario que la directiva sea un objeto con los hooks que quieres usar.

Veamos un ejemplo de directiva llamada focus que lo que hace es poner el foco en el navegador sobre el elemento en el que se inserta la directiva. Para ello uso el hook bind para porder hacer el focus al crearse el elmento en el DOM:

Vue.directive('focus', {
  // Cuando el elemento enlazado se inserta en el DOM...
  inserted: function (el) {
    // Enfoca el elemento
    el.focus()
  }
})

Parámetros de los hooks

Cada uno de los hooks antes mencionados pueden recibir como parámetro de la función lo siguiente:

  • el: El elemento del DOM sobre el que se aplica la directiva
  • binding: Objeto solo de lectura que contiene información que puede recibir la directiva
  • vnode: Objeto solo de lectura que contiene el nodo del virtual dom asociado a la directiva
Vue.directive('hooks', {
  bind: function(el, binding, vnode) {
    console.log(el);
    console.log(binding);
    console.log(vnode);
  }
})

Pasar información a las directivas

Como hemos dicho antes, v-show y v-if son directivas por lo que el paso de infotmación a las directivas es igual a estas dos. Todo lo que pongas dentro al llamar a la directiva es código javascript, métodos o variables y propiedades computadas. Por ejemplo

<div v-color="'red'"></div>
<div v-color="getColor()"></div>

Ahora bien, para usar este valor que pasas dentro de la directiva, tienes que usar el parámetro binding visto anteriormente. Dentro de este parámetro puedes acceder a su propiedad value para recoger el valor que pasas desde la directiva. Por ejemplo:

Vue.directive("color", {
  inserted: function(el, binding, vnode) {    
    el.style.color = binding.value;
  }
})

Argumentos

Las directivas de Vue también aceptan argumentos. Los argumentos en vue se usan poniendo dos puntos después del nombre de la directiva. Por ejemplo:

<app-navigation v-sticky:bottom></app-navigation>

Para usar este valor dentro de la directiva tenemos que usar la propiedad arg que viene dentro del objeto binding:

Vue.directive("sticky", 
  function(el, binding, vnode) {    
    console.log(binding.arg);
});

Modificadores

También puedes usar modificadores en las directivas. Para usarlos es simplemente poniendo un punto después del nombre de la directiva y a continuación el nombre del modificador:

<div v-test.foo></div>

Dentro de la directiva, puedes recoger los modificadores así:

Vue.directive("sticky", 
  function(el, binding, vnode) {  
    const modifiers = binding.modifiers;  
    console.log(modifiers);
});

Los modificadores normalmente se usan para eventos o directivas nativas, por ejemplo: click.stop.

Directivas interesantes

v-click-outside

Sirve para detectar cuando se hace click fuera de un elemento del HTML. Esta directiva suele ser especialmente útiles en popups. Cuando el usuario hace click fuera del popup puedes ejecutar una función para ocultarlo:

<div v-click-outside="onClickOutside"></div>

https://github.com/ndelvalle/v-click-outside

v-hotkey

Sirve para poder hacer bindeos de teclas. Por ejemplo puedes hacer que al pulsar Esc se cierre un popup o que con cierta combinación de teclas ocurra algo:

<template>
  <span v-hotkey="keymap" v-show="show"> Press `ctrl + esc` to toggle me! Hold `enter` to hide me! </span>
</template>

<script>
export default {
  data () {
    return {
      show: true
    }
  },
  methods: {
    toggle () {
      this.show = !this.show
    },
    show () {
      this.show = true
    },
    hide () {
      this.show = false
    }
  },
  computed: {
    keymap () {
      return {
        // 'esc+ctrl' is OK.
        'ctrl+esc': this.toggle,
        'enter': {
          keydown: this.hide,
          keyup: this.show
        }
      }
    }
  }
}
</script>

https://github.com/Dafrok/v-hotkey

v-clipboard

Simplemente añade la funcionalidad de copiar al portapapeles cuando se pulsa el botón:

<button v-clipboard="value">
  Copy to clipboard
</button>

https://github.com/Inndy/vue-clipboard2

v-lazyload

Esto del lazyload es una cosa muy recomendable en cualquier web, sobre todo si tienes muchas imágenes. De lo que se trata es que las imágenes solo se carguen si están dentro del campo de visión del usuario, es decir, si hay imágenes debajo del scroll, solo se cargarían cuando entren en pantalla, cosniguiendo que la web cargue más rápido.

Para implementar lazyload tienes que poner la ruta a tu imagen dentro del atributo v-lazy, pero cuaidado, no pongas el atributo src de la imagen para que no se cargue sola.

<img v-lazy="https://www.domain.com/image.jpg">

https://github.com/hilongjw/vue-lazyload

Conclusiones

Las directivas pueden llegar a ser muy potentes y te pueden salvar más de una vez de tener que añadir más código. Lo bueno como siempre, es que son reutilizables y vas a hacer que el código sea más mantenible.

Por cierto, que se me olvidaba, puedes declarar directivas de forma local también dentro de un solo componente, de tal forma que solo sea accesible para ese componente en particular. Para ello tienes que crear la directiva o importarla dentro de la propiedad directives del componente.