n How to create custom directives in Vue.js | CodimTh

Please Disable Your Browser Adblock Extension for our site and Refresh This Page!

our ads are user friendly, we do not serve popup ads. We serve responsible ads!

Refresh Page
Skip to main content
On . By CodimTh
Category:

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).

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:

 

// 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

A directive definition object can provide several hook functions (all optional):

  • bind: called only once, when the directive is first bound to the element. This is where you can do one-time setup work.

  • inserted: called when the bound element has been inserted into its parent node (this only guarantees parent node presence, not necessarily in-document).

  • update: called after the containing component’s VNode has updated, but possibly before its children have updated. The directive’s value may or may not have changed, but you can skip unnecessary updates by comparing the binding’s current and old values (see below on hook arguments).

  • componentUpdated: called after the containing component’s VNode and the VNodes of its children have updated.

  • unbind: 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 hooks are passed these arguments:

  • el: The element the directive is bound to. This can be used to directly manipulate the DOM.
  • binding: An object containing the following properties.
    • name: The name of the directive, without the v- prefix.
    • value: The value passed to the directive. For example in v-my-directive="1 + 1", the value would be 2.
    • oldValue: The previous value, only available in update and componentUpdated. It is available whether or not the value has changed.
    • expression: The expression of the binding as a string. For example in v-my-directive="1 + 1", the expression would be "1 + 1".
    • arg: The argument passed to the directive, if any. For example in v-my-directive:foo, the arg would be "foo".
    • modifiers: An object containing modifiers, if any. For example in v-my-directive.foo.bar, the modifiers object would be { foo: true, bar: true }.
  • vnode: The virtual node produced by Vue’s compiler. See the VNode API for full details.
  • oldVnode: The previous virtual node, only available in the update and componentUpdated hooks.

 

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:

 

<div id="baseexample">
  <p>Scroll down the page</p>
  <p v-pin="200">Stick me 200px from the top of the 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'
})

 

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:

 

<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>

 

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.

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

 

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

 

Can Vue.js custom directive be implemented as individual files?

 

A directive is only a class with a few well-defined methods. In JS, you can write something like :

export const MyDirective {
    bind(el,binding,vnode) {
        /* your code */
    }
}

 

then, in the file where you use it :

<template>
    <p v-app-my-directive:arg.modifier="value">Some Text</p>
</template>
<script>
    import MyDirective from './directives/MyDirective.js';

    export default {
        directives: {
            AppMyDirective: MyDirective
        }
        /* ... */
    }
</script>

 

You can also use

Vue.directive('app-my-directive', MyDirective)

to declare it globally.

 

Riadh Rahmi

Senior Web Developer PHP/Drupal & Laravel

I am a senior web developer, I have experience in planning and developing large scale dynamic web solutions especially in Drupal & Laravel.

Web Posts

Search

Page Facebook