Directives personnalisées

Introduction

En supplément de l’ensemble de directives fournies par défaut (v-model et v-show), Vue vous permet également d’enregistrer vos propres directives. Notez qu’avec Vue 2.0, les composants sont la forme principale de réutilisabilité et d’abstraction du code. Il y a cependant des cas où vous aurez juste besoin d’un accès de bas niveau aux éléments du DOM, et c’est là que les directives personnalisées vous seraient utiles. Un exemple pourrait être la prise du focus sur un élément de champ, comme celui-ci :

Quand la page se charge, cet élément prend le focus (notez que autofocus ne fonctionne pas sur Safari mobile). En fait, si vous n’avez cliqué sur rien du tout depuis votre arrivée sur la page, le champ ci-dessus devrait avoir le focus. À présent, jetons un œil à la directive qui pourrait accomplir cela :

// Enregistrer une directive globale appelée `v-focus`
Vue.directive('focus', {
  // Quand l'élément lié est inséré dans le DOM...
  inserted: function (el) {
    // L'élément prend le focus
    el.focus()
  }
})

Si vous préférez enregistrer à la place la directive en local, les composants acceptent également l’option directives :

directives: {
  focus: {
    // définition de la directive
    inserted: function (el) {
      el.focus()
    }
  }
}

Puis dans un template, vous pouvez utiliser le nouvel attribut v-focus sur n’importe quel élément, comme celui-ci :

<input v-focus>

Fonctions de hook

Un objet de définition de directive peut fournir plusieurs fonctions de hook (toutes optionnelles) :

Nous couvrerons VNodes plus en détail plus tard, quand nous discuterons des fonctions de rendu.

Nous allons explorer les arguments passés à ces hooks (c.-à-d. el, binding, vnode, et oldVnode) dans la prochaine section.

Arguments des hooks d’une directive

Les hooks d’une directive ont accès à ces arguments :

À l’exception de el, vous devez traiter ces arguments comme étant en lecture seule (« read-only ») et ne jamais les modifier. Si vous souhaitez partager des informations entre les hooks, il est recommandé de le faire à travers les attributs de données sur mesure de ses éléments (voir dataset).

Un exemple de directive personnalisée utilisant plusieurs de ces propriétés :

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})

new Vue({
  el: '#hook-arguments-example',
  data: {
    message: 'bonjour !'
  }
})

Arguments de directive dynamiques

Les arguments de directive peuvent être dynamiques. Par exemple, dans v-mydirective:[argument]="value", l’argument peut-être mis à jour en se basant sur la propriété de donnée dans notre instance de composant ! Cela rend nos directives personnalisées flexibles à travers notre application.

Imaginons que vous vouliez créer une directive personnalisée qui vous permet d’attacher des éléments sur votre page en utilisant le positionnement fixe. Nous pourrions créer une directive personnalisée ou la valeur met à jour le positionnement vertical en nombre de pixel, comme ceci :

<div id="baseexample">
  <p>Faite défiler la page vers le bas ↓</p>
  <p v-pin="200">Je suis attaché à 200px depuis le haut de page.</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    el.style.top = binding.value + 'px'
  }
})

new Vue({
  el: '#baseexample'
})

Cela va attacher l’élément à 200px depuis le haut de la page. Mais que ce passe t-il si nous somme dans un scénario ou nous avons besoin d’attacher l’élément sur la gauche à la place du haut ? Ici nous avons un argument dynamique qui peut être mis à jour pour chaque instance du composant de manière très pratique :

<div id="dynamicexample">
  <h3>Faite défiler la page vers le bas ↓</h3>
  <p v-pin:[direction]="200">Je suis attaché à 200px depuis la gauche de la page.</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    var s = (binding.arg == 'left' ? 'left' : 'top')
    el.style[s] = binding.value + 'px'
  }
})

new Vue({
  el: '#dynamicexample',
  data: function () {
    return {
      direction: 'left'
    }
  }
})

Résultat :

Nos directives personnalisées sont maintenant assez flexibles pour supporter différents cas d’utilisation.

Fonction abrégée

Dans de nombreux cas, vous pourriez vouloir le même comportement pour les hooks bind et update, sans avoir besoin des autres hooks. Par exemple :

Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})

Objets littéraux

Si votre directive a besoin de plusieurs valeurs, vous pouvez également passer un objet JavaScript. Souvenez-vous, une directive peut accepter n’importe quelle expression JavaScript.

<div v-demo="{ color: 'white', text: 'bonjour !' }"></div>
Vue.directive('demo', function (el, binding) {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text)  // => "bonjour !"
})