Diretivas Personalizadas

Introdução

Adicionalmente ao conjunto de diretivas incluídas em seu núcleo (v-model e v-show), Vue permite registrar suas próprias diretivas personalizadas. Note que no Vue 2.0, a forma primária de abstração e reuso de código são componentes - no entanto, pode haver casos em que você só precisa de um acesso de baixo nível ao DOM em elementos simples, e aí diretivas personalizadas seriam úteis. Um exemplo seria colocar o foco a um elemento input como este:

Quando a página carrega, o elemento ganha o foco (nota: o atributo nativo autofocus não funciona no Safari para dispositivos móveis). Na verdade, se você ainda não clicou em nada desde que visitou esta página do guia, o input acima deverá estar com o foco. Agora vamos construir a diretiva que realiza isto:

// Registra a diretiva personalizada global chamada `v-focus`
Vue.directive('focus', {
  // Quando o elemento vinculado é inserido no DOM...
  inserted: function (el) {
    // Coloque o foco no elemento
    el.focus()
  }
})

Se você deseja registrar uma diretiva localmente em vez disso, os componentes também aceitam uma opção directives:

directives: {
  focus: {
    // definição da diretiva
    inserted: function (el) {
      el.focus()
    }
  }
}

Então, em um template você pode usar o novo atributo v-focus para qualquer elemento, por exemplo:

<input v-focus>

Funções de Gatilhos

Um objeto de definição de diretiva pode prover algumas funções de gatilhos (todas opcionais):

Abordaremos o VNodes com mais detalhes depois, quando discutirmos funções de renderização.

Iremos a seguir explorar os argumentos que podem ser passados nessas funções de gatilho (el, binding, vnode, e oldVnode).

Argumentos nos Gatilhos

Os seguintes argumentos são esperados nas funções de gatilho das diretivas:

Exceto el, você deve tratar os outros argumentos como somente leitura e nunca modificá-los. Se você precisar compartilhar informações entre gatilhos, é aconselhável utilizar um atributo dataset.

Eis um exemplo de diretiva personalizada utilizando algumas dessas propriedades:

<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: 'Olá!'
  }
})

Argumentos de Diretiva Dinâmicos

Os argumentos de diretiva podem ser dinâmicos. Por exemplo, em v-mydirective:[argument]="value", o argument pode ser atualizado baseado em propriedades de dados em nossa instância de componente! Isso torna nossas diretivas personalizadas flexíveis para serem utilizadas ao longo da aplicação.

Digamos que você quer fazer uma diretiva personalizada que permite fixar elementos em sua página através de posicionamento fixed. Poderíamos criar uma diretiva personalizada em que os valores atualizassem o posicionamento vertical em pixels, desta forma:

<div id="baseexample">
  <p>Role a página para baixo</p>
  <p v-pin="200">Me prenda 200px a partir do topo da página</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    el.style.top = binding.value + 'px'
  }
})

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

Isto fixaria o elemento 200px a partir do topo da página. Mas e se encontrássemos um cenário em que precisássemos fixar o elemento a partir da esquerda, ao invés do topo? Aqui está um argumento dinâmico que pode ser atualizado em cada instância de componente:

<div id="dynamicexample">
  <h3>Role para baixo dentro desta seção ↓</h3>
  <p v-pin:[direction]="200">Estou fixo na página 200px a partir da esquerda.</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'
    }
  }
})

Resultado:

Nossa diretiva personalizada agora é flexível o suficiente para suportar alguns casos de uso diferentes.

Forma Abreviada de Funções

Em muitos casos, você pode querer ter o mesmo comportamento nos gatilhos bind e update, e não se importar com os outros gatilhos. Por exemplo:

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

Objetos Literais

Se sua diretiva precisa de múltiplos valores, você pode passá-los em um objeto literal JavaScript. Lembre-se que as diretivas podem ter qualquer objeto JavaScript válido.

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