Basis
In addition to the built-in directives, Vue.js also allows the registration of custom directives. A custom directive provides a mechanism to map changes in data to DOM behavior.
You can Vue.directive(id, definition)
register a global custom directive with a method that receives two parameter instruction IDs and definition objects . You can also directives
register a local custom directive with the component's options.
hook function
The definition object can provide several hook functions (all optional):
bind: Called only once, when the instruction is first bound to the element.
Update: bind
immediately after the first call with the initial value for the parameter, and then whenever the binding value changes, the parameter is the new value and the old value.
unbind: Called only once, when the instruction is unbound from the element.
Example
Vue.directive(‘my-directive‘, { bind: function () { // 准备工作 // 例如,添加事件处理器或只需要运行一次的高耗任务 }, update: function (newValue, oldValue) { // 值更新时的工作 // 也会以初始值为参数调用一次 }, unbind: function () { // 清理工作 // 例如,删除 bind() 添加的事件监听器 }})
After registering, you can use this in the Vue.js template (remember to add a prefix v-
):
<div v-my-directive="someValue"></div>
When you need only update
a function, you can pass in a function substitution definition object:
Vue.directive(‘my-directive‘, function (value) { // 这个函数用作 update()})
Instruction Instance Properties
All the hook functions are copied to the actual instruction object , and the hooks this
point to the instruction object. This object exposes a number of useful properties:
- El: The element that the directive binds to.
- VM: The context ViewModel that owns the directive.
- expression: Expressions for directives, excluding parameters and filters.
- arg: The parameter of the directive.
- Name: The directive is named, and does not contain a prefix.
- modifiers: An object that contains the modifier of the directive.
- Descriptor: An object that contains the parsing result of the instruction.
You should treat these properties as read-only and do not modify them. You can also add custom attributes to a directive object, but be careful not to overwrite existing internal properties.
Example:
<div id="demo" v-demo:hello.a.b="msg"></div>
Vue.directive (' demo ', {bind:function() {Console.log (' Demo bound! ') }, UPDATE:function(value) { This.el.innerHTML = ' name-' + this.name + ' <br> ' + ' expression-' + This.ex pression + ' <br> ' + ' argument-' + This.arg + ' <br> ' + ' modifiers-' + Json.strin Gify (this.modifiers) + ' <br> ' + ' value-' + value} 'var demo = New Vue ({el: ' #demo ') , data: {msg: ' hello! '}})
Object literal
If the instruction requires more than one value, you can pass in a JavaScript object literal. Remember that directives can use any of the legitimate JavaScript expressions:
<div v-demo="{ color: ‘white‘, text: ‘hello!‘ }"></div>
Vue.directive(‘demo‘, function (value) { console.log(value.color) // "white" console.log(value.text) // "hello!"})
literal modifier
When the instruction uses a literal modifier, its value is treated as a normal string and passed to the update
method. update
method will be called only once because normal strings cannot respond to data changes.
<div v-demo.literal="foo bar baz">
Vue.directive(‘demo‘, function (value) { console.log(value) // "foo bar baz"})
ELEMENT directive
Sometimes we want to use directives in the form of custom elements, rather than in the form of attributes. This is very similar to Angular's "E" directive. An element directive can be seen as a lightweight component. You can register a custom element directive like this:
Vue.elementDirective(‘my-directive‘, { // API 同普通指令 bind: function () { // 操作 this.el... }})
Don't write like this:
<div v-my-directive></div>
Write this:
<my-directive></my-directive>
An element directive cannot accept arguments or expressions, but it can read the attributes of an element to determine its behavior.
Unlike ordinary instructions, an element directive is summative , which means that once Vue encounters an element directive, it skips the element and its child elements--only the element instruction itself can manipulate the element and its child elements.
Advanced options Params
Custom directives can receive an params
array, specify a list of attributes, and the Vue compiler will automatically extract these attributes of the binding element. For example:
<div v-example a="hi"></div>
Vue.directive(‘example‘, { params: [‘a‘], bind: function () { console.log(this.params.a) // -> "hi" }})
This API also supports dynamic properties. this.params[key]
is automatically kept up to date. Alternatively, you can specify a callback to invoke when the value changes:
<div v-example v-bind:a="someValue"></div>
Vue.directive(‘example‘, { params: [‘a‘], paramWatchers: { a: function (val, oldVal) { console.log(‘a changed!‘) } }})
Similar to props, the name of the directive parameter is used in JavaScript CamelCase style, corresponding to the use of kebab-case style in HTML. For example, suppose there is a parameter ' disable-effect ' in the template that accesses it in JavaScript with ' Disableeffect '.
Deep
If the custom directive is used on an object, update
it is specified in the directive definition object when the object's internal property changes to be triggered deep: true
.
<div v-my-directive="obj"></div>
Vue.directive(‘my-directive‘, { deep: true, update: function (obj) { // 在 `obj` 的嵌套属性变化时调用 }})
TwoWay
If the directive wants to write back data to the Vue instance, it is specified in the directive definition object twoWay: true
. This option allows for use in directives this.set(value)
:
Vue.directive (' Example ', {twoWay:True, bind:function () {this.handler = function () { //writes data back to VM //if the directive binds v-example= "A.B.C" //It will be set with the given value ' VM.A.B.C ' this.set (this.el.value )}.bind (this) this.el.addeventlistener ( this.handler)}, Unbind: function () {this.el.removeeventlistener (
Acceptstatement
Incoming acceptStatement:true
allows custom directives to accept inline statements, just like v-on
that:
<div v-my-directive="a++"></div>
Vue.directive(‘my-directive‘, { acceptStatement: true, update: function (fn) { // 传入值是一个函数 // 在调用它时将在所属实例作用域内计算 "a++" 语句 }})
Use wisely, because usually you want to avoid the side effects in the template.
Terminal
1.0.19+
Vue compiles the module by recursively traversing the DOM tree. But when it encounters the terminal instruction, it stops traversing the descendant elements of the element. This command will take over the task of compiling the element and its descendants. v-if
and v-for
both are terminal instructions.
Writing a custom terminal directive is a high-level topic that requires a good understanding of the Vue compilation process, but this is not to say that it is not possible to write custom terminal directives. You terminal: true
may also need to compile partial with the specified custom terminal Directive Vue.FragmentFactory
. Here is a custom terminal directive that compiles its content template and injects the results to another place on the page:
var fragmentfactory = Vue.fragmentfactoryvar remove = Vue.util.removevar createanchor = Vue.util.createAnchorVue.directive (' Inject ', {terminal:True, bind:function() {var container = document.getElementById (this.arg) this.anchor = Createanchor ( ' V-inject ') container.appendchild (this.anchor) Remove (this.el) var factory = new Fragmentfactory (THIS.VM, this.el) this.frag = factory.create (this._host, this._scope, this._frag) This.frag.before (this.anchor)}, Unbind: function () {this.frag.remove () Remove (this.anchor)})
< div id= "modal" > </DIV> <div v-inject:modal> <h1>header</ h1> <p>body </p> < P>footer</p></DIV>
If you want to write custom terminal instructions, it is recommended that you read through the source code of the built-in terminal instructions, such as v-if
and v-for
, to better understand the internal mechanism of Vue.
Priority
You can assign a priority to the directive. If not specified, the normal instruction is by default 1000
, the terminal directive is the default 2000
. Commands with higher precedence on the same element will be processed earlier than other directives. Commands with the same precedence are processed sequentially in the order in which they appear in the list of element attributes, but there is no guarantee that the order will be consistent across browsers.
You can view the priority of built-in directives in the API. In addition, the Process Control directives v-if
and v-for
always have the highest priority during the compilation process.
Vue.js Learning item13– instruction system and custom directives