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:
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
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 is2
.oldValue
: The previous value bound by the directive, only available inupdate
andcomponentUpdated
hooks. Available regardless of whether the value has changed.#expression
: Instruction expression in string form. For example, inv-my-directive="1 1"
, the expression is"1 1"
.arg
: Parameters passed to the command, optional. For example, inv-my-directive:foo
, the parameter is"foo"
.modifiers
: An object containing modifiers. For example: Inv-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 inupdate
andcomponentUpdated
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'sdataset
.
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!' } })
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:
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