Custom Directives in Vue 3

Custom Directives in Vue 3

In addition with default directive, we could also create and use custom directive in Vue.js. If you remember, firstly you can compare these directives with HTML Boolean attributes. Something similar to disabled attribute. The disabled attribute makes HTML element unusable and un-clickable. Ultimately it brings some execution on the elements. Similarly, The custom directive brings some execution on the relevant DOM elements. We can define custom directive as an object containing lifecycle hooks similar to those of a component. Below is the very simple use case,

const focus = {
  mounted: (el) => el.focus()
}

export default {
  directives: {
    // enables v-focus in template
    focus
  }
}

We can use above directive in the template like below,

<input v-focus />

This is a simple example, we can do lot more with this directives. But, here it will focus the input element assuming you haven’t clicked elsewhere on the page. Let’s take the deep dive into it.

Custom Directives in Vue

Global Directive Registration

In the above example, we are using local registration. In addition, similar to components, we can globally register custom directives in the application instance. So that we can use the directives through out the application in the templates.

const app = createApp({})

// make v-focus usable in all components
app.directive('focus', {
  /* ... */
})

However, we can prefer to use custom directives only when the desired functionality can only be achieved via direct DOM manipulation. Otherwise we could use v-bind because they are more efficient and server-rendering friendly.

Custom Directives in Vue 3 – Hooks

The directive object is providing lot of optional hook functions. For Instance, we would use this hooks to manipulate the DOM, read the old value, component instance and vnode representation as well.

const myDir = {
  // called before bound element's attributes
  // or event listeners are applied
  created(el, binding, vnode, prevVnode) {
    // see below for details on arguments
  },
  // called right before the element is inserted into the DOM.
  beforeMount() {},
  // called when the bound element's parent component
  // and all its children are mounted.
  mounted() {},
  // called before the parent component is updated
  beforeUpdate() {},
  // called after the parent component and
  // all of its children have updated
  updated() {},
  // called before the parent component is unmounted
  beforeUnmount() {},
  // called when the parent component is unmounted
  unmounted() {}
  }
}

Hook Arguments

  • el – We can use el to manipulate the DOM
  • binding – it is an object having lot of properties
    • value – the value of the directive. Example, v-my-directive=”VALUE”
    • oldValue – the old value of the directive. only available in beforeUpdate and updated
    • arg – the argument of the directive. Example, v-my-directive:foo
    • instance – the instance of the component
    • dir – the definition object of directive
    • modifiers – the modifier object. Example v-my-directive:foo:bar. Here  the modifiers object would be { foo: true, bar: true }
  • vnode – The V Node representation of the element
  • prevNode – The element of previous render. Only available in the beforeUpdate and updated hooks

Consider the below example,

<div v-example:foo.bar="baz">

// we can represent above directive as below object

{
  arg: 'foo',
  modifiers: { bar: true },
  value: /* value of `baz` */,
  oldValue: /* value of `baz` from previous update */
}

// binding value as JavaScript object literal

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

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

Dynamic Argument in Directives

We can also pass dynamic argument to the directives. This is one of the special feature of directive. For example,

<div v-example:[arg]="value"></div>

// Here the directive argument will be reactively updated 
   based on arg property in our component state.

Most important this here is , other than el, we should not modify other read-only properties. If you want so, you can follow this dataset

Function Shorthand

If we wants only mounted and updated behavior of custom directives, then we can use function shorthand there.

<div v-color="color"></div>

app.directive('color', (el, binding) => {
  // this will be called for both `mounted` and `updated`
  el.style.color = binding.value
})

Custom Directives in Vue 3 – on Component

As similar to DOM elements, we can use custom directives on component as well. Here It will apply to a component root element. Note that, sometimes the component may have more than one root node. If so, it will ignore the directives and a warning will be shown. Above all, it is not preferable to use custom directives on component.

<MyComponent v-demo="test" />

<!-- template of MyComponent -->

<div> <!-- v-demo directive will be applied here -->
  <span>My component content</span>
</div>

With Directives

In Addition, we can apply custom directives to v-node using withDirectives as follows,

import { h, withDirectives } from 'vue'

// a custom directive
const pin = {
  mounted() { /* ... */ },
  updated() { /* ... */ }
}

// <div v-pin:top.animate="200"></div>
const vnode = withDirectives(h('div'), [
  [pin, 200, 'top', { animate: true }]
])

Summary

In Conclusion,

  • Firstly, the custom directive brings some execution on the elements. We can define custom directive as an object containing lifecycle hooks similar to those of a component.
  • Use custom directives only when the desired functionality can only be achieved via direct DOM manipulation.
  • You would pass dynamic argument to the directives. This is one of the special feature of directive.

References

 

Leave a Reply

%d bloggers like this: