URL: https://www.progressiverobot.com/vuejs-custom-directives/

When you talk about Vue.js, you usually talk about Components. Components, components, components. Components aren't the only thing you can write with Vue though, and it's a good thing too. What if you want to apply modifiers to your components? That's where directives come in. Whether you knew it or not, you've been using them already. <^>v-if<^>, <^>v-model<^>, and <^>v-for<^> are all examples of directives. Today, we're going to show you how to add an important directive that performs a critical task that we can't live without. Setting the background of its element to a nice baby blue.

Creating a Directive

directives illustration for: Creating a Directive

Let's get right on into the thick of it then. Create a new file called <^>AnnoyingBackgroundDirective.js<^>.

Now, let's write the directive. A directive is just an object with a few special functions on it.

				
					
[label AnnoyingBackgroundDirective.js]

import Vue from 'vue';



const defaultBackgroundColor = '#86bbff'



// Initialize the annoying-background directive.

export const AnnoyingBackground = {

  bind(el, binding, vnode) {

    // Allow users to customise the color by passing an expression.

    const color = binding.expression || defaultBackgroundColor



    // el might not be present for server-side rendering.

    if (el) {

      // Set the element's background color.

      el.style.backgroundColor = color

    }

  }

}



// You can also make it available globally.

Vue.directive('annoying-background', AnnoyingBackground)

				
			

Now to use it in a component, simply add it to your component template prefixed with a <^>v-<^>.

				
					
[label TotallyNormalComponent.vue]

&lt;template&gt;

  &lt;div&gt;

    &lt;p v-annoying-background&gt;Baby blue looks good on me.&lt;/p&gt;

    &lt;p v-annoying-background="#0f0"&gt;I prefer neon green.&lt;/p&gt;

  &lt;/div&gt;

&lt;/template&gt;



&lt;script&gt;

import { AnnoyingBackground } from './AnnoyingBackgroundDirective.js';



export default {

  directives: {

    AnnoyingBackground

  }

}

&lt;/script&gt;

				
			

More Details

A directive has five possible hooks:

  • bind(element, binding, vnode) – Called when the directive is first bound to the component or element.
  • inserted(element, binding, vnode) – Called when the component or element is inserted into it's parent node. It may not be in the DOM yet.
  • update(element, binding, vnode, oldVnode) – Called when the containing component has updated but potentially before its children do.
  • componentUpdated(element, binding, vnode, oldVnode) – Called when the containing component has updated but after its children do.
  • unbind(element, binding, vnode) – Called when the directive is unbound from the component or element.

The arguments are these:

  • element – The element the directive is bound to. May be undefined.
  • binding – (This is the fun one.) Contains any arguments, values, and modifiers passed to the directive.
  • binding.name – The name of the directive.
  • binding.value – The value of a JS expression passed to the directive, if any. (ie. v-directive="{cake: 'chocolate'}" <^>-><^> binding.value.cake === 'chocolate')
  • binding.oldValue – The previous value of the directive, only provided in update and componentUpdated.
  • binding.expression – The value expression as a string: v-directive="{cake: 'chocolate'}" <^>-><^> binding.expression === '{cake: 'chocolate'}'
  • binding.arg – The argument passed to the directive, if any. v-directive:myArg <^>-><^> binding.arg === 'myArg'
  • binding.modifiers – An object containing any modifiers passed to the directive as booleans. v-directive.modifier.modifier2 <^>-><^> JSON.stringify(binding.modifiers) === {"modifier": true, "modifier2": true}
  • vnode – This is a virtual node used by Vue's renderer. Don't touch this unless you know what you're doing. 😛
  • oldVnode – The previous version of the above vnode. Only available in the update hooks.

So yeah, directives are really simple to create, but you can do a lot of crazy stuff with them if you so wish. Here's the documentation.

Bonus Round

  • Try creating a conditional directive! Hint: You'll probably need to hook into the vNode API. Sorry.

[itemprop=articleSection] ul ul li::before { content: ""; left: 36px; margin-top: 9px; position: absolute; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-left: 4px solid #EFBB35; border-top: 4px solid #EFBB35; border-bottom: 4px solid #EFBB35; border-right: 4px solid #EFBB35; } [itemprop=articleSection] ul ul li, [itemprop=articleSection] ul ul li code { font-size: 1rem; } <style> </div>