Custom instructions


Table of Contents


Introduction


##In addition to the core functions, the default built-in instructions (

v-model and v-show), Vue also allows the registration of custom directives. Note that in Vue2.0, the main form of code reuse and abstraction is components. However, in some cases, you still need to perform low-level operations on ordinary DOM elements, in which case custom directives are used. Take an example of a focused input box, as follows:

4.gif

When the page loads, the element will gain focus (Note:

autofocus is moving Doesn't work on Safari version). In fact, as long as you haven't clicked on anything after opening this page, the input box should still be focused. Now let's use directives to implement this function:

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

If you want to register local directives, the component also accepts a

directives option:

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

Then you can Use the new

v-focus attribute on any element, as follows:

<input v-focus>


Hook function


A command definition object can provide the following hook functions (all optional):


  • bind: Called only once, the first time the directive is bound to an element. One-time initialization settings can be performed here.

  • inserted: Called when the bound element is inserted into the parent node (only the parent node is guaranteed to exist, but not necessarily inserted into the document).

  • update: Called when the VNode of the component is updated, but it may occur before its child VNode is updated. The value of the directive may or may not have changed. But you can ignore unnecessary template updates by comparing the values ​​before and after the update (see below for detailed hook function parameters).

We will introduce more details of VNodes when

laterdiscussrendering functions.

  • componentUpdated: Called after all the VNode and its sub-VNode of the component where the instruction is located have been updated.

  • unbind: Called only once, when the instruction is unbound from the element.

Next let’s take a look at the parameters of the hook function (i.e. el, binding, vnode and oldVnode).


Hook function parameters


The command hook function will be passed in the following parameters:

  • el: The element bound to the instruction can be used to directly manipulate the DOM.

  • binding: An object containing the following attributes:

    • name: Instruction name, Does not include the v- prefix.

    • value: The binding value of the directive, for example: v-my-directive="1 1", the binding value is 2.

    • oldValue: The previous value bound by the directive, only available in update and componentUpdated hooks. Available regardless of whether the value has changed.

    • #expression: Instruction expression in string form. For example, in v-my-directive="1 1", the expression is "1 1".

    • arg: Parameters passed to the command, optional. For example, in v-my-directive:foo, the parameter is "foo".

    • modifiers: An object containing modifiers. For example: In v-my-directive.foo.bar, the modifier object is { foo: true, bar: true }.

  • vnode: The virtual node generated by Vue compilation. Move to VNode API to learn more details.

  • oldVnode: The previous virtual node, only available in update and componentUpdated hooks.

Except el, all other parameters should be read-only and must not be modified. If you need to share data between hooks, it is recommended to do it through the element's dataset.

This is an example of a custom hook that uses these properties:

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

1.jpg


Dynamic command parameters

The parameters of the directive can be dynamic. For example, in v-mydirective:[argument]="value", the argument parameter can be updated based on component instance data! This allows custom directives to be used flexibly in applications.

For example, you want to create a custom directive to fix elements on the page through fixed layout. We can create a custom directive that updates the vertical pixel value by the directive value like this:

<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 will fix the element at a position of 200 pixels from the top of the page. But what if the scenario is that we need to fix the element to the left instead of the top? At this time, dynamic parameters can be used to update each component instance very conveniently.

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

Result:

1.gif

This way this custom directive is now flexible enough to support a few different use cases.


Function abbreviation


In many cases, you may want to use bind and update trigger the same behavior, regardless of other hooks. For example, write like this:

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


Object literal


If the instruction requires multiple values , you can pass in a JavaScript object literal. Remember, directive functions accept all legal JavaScript expressions.

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