w3resource

Custom Directives

Vue also allows us to register our own custom directives aside the default set of directives that are shipped in core (v-show and v-model). In Vue 2.0, the primary code reuse and abstraction is components- however there may be cases where we need some low-level DOM access on plain elements, custom directives will still be useful here. A typical example would be focusing on an input element, like an input text.

On page load, the element gains focus (Note: autofocus does not work on mobile safari). If one has not clicked on anything else since visiting the page, the text input should be focused. Let us build the directive that will accomplish this:

JS

// Registering a global custom directive called `v-focus`
Vue.directive('focus', {
  // When the bound element is inserted into the DOM...
  inserted: function (el) {
    // Focus the element
    el.focus()
  }
})

Instead if we want to register a directive locally, components accept directives option as well:

directives: {
  focus: {
    // directive definition
    inserted: function (el) {
      el.focus()
    }
  }
}

Then we can now use the new v-focus attribute on any element in our template as shown:

<input v-focus>

Hook Functions

Several hook functions can be provided by a directive's definition object:

  • bind: this is called only once, when the directive is first bound to the element. This is where we can do one-time setup work.
  • inserted: this is called when the bound element has been inserted into its parent node (this only guarantees the parent node presence, not necessarily in-document).
  • update: this is called after the containing component's VNode has updated, but possibly before the update of its children. The value of the directive may or may not have changed, but we can skip unnecessary updates by comparing the binding's current and old values (see hook arguments below).
  • componentUpdated: this is called after the containing component's VNode and the VNodes of its children have updated.
  • unbind: this is called only once, when the directive is unbound from the element.

In the next section we will explore the arguments passed into these hooks.

Directive Hook Arguments

directive arguments are not always static; they can be dynamic. For instance, in v-mydirective:[argument]="value", the argument can be updated based on the data properties in our component instance!. Thus our custom directives are flexible throughout our application.

Let's say we want to make a custom directive that allows us to pin elements to our page using fixed positioning. We could create a custom directive where the value will update the vertical positioning in pixel, as shown below:

HTML

<div id="baseexample">
  <p>Scroll down the page</p>
  <p v-pin="200">Stick me 200px from the top of the page</p>
</div>

JS

Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    el.style.top = binding.value + 'px'
  }
})
new Vue({
  el: '#baseexample'
})

This snippet will pin the element 200px from the top of the page. How about when we need to pin the element from the left and not from the top? Using a dynamic argument that can be updated per component instance will come in very handy:

HTML

<div id="dynamicexample">
  <h3>Scroll down inside this section ?</h3>
  <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>

JS

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'
    }
  }
})

With this our custom directive is flexible enough to support different use cases.

Function Shorthand

There are so many cases when we may want the same behavior on bind and update, and don't care about other hooks. For instance:

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

Object Literals

If our directive needs multiple values, we can also pass in a JavaScript object literal.

HTML

<div v-demo="{ color: 'white', text: 'hello!' }"></div>

JS

Vue.directive('demo', function (el, binding) {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text)  // => "hello!"
})


Inviting useful, relevant, well-written and unique guest posts