在Vue中可以自定义指令,通过自定义指令,我们可以对DOM进行更多的底层操作,这样不仅可以在某些场景下为我们提供快速解决问题的思路,而且让我们对Vue的底层有了进一步的了解。
我们可以通过Vue.directive({})
或者directives:{}
来定义指令。具体如下:
// 定义全局指令
Vue.directive("指令名称", {})
// 定义当前模版下指令
var vm = new Vue({
...
directives: {
// 定义指令
}
})
一个指令定义对象可以提供如下几个钩子函数(均为可选):
钩子 | 说明 |
---|---|
bind | 此钩子函数只会被调用一次,可以定义一个在绑定时执行一次的初始化动作 |
inserted | 当被绑定的元素插入到父元素中时调用(此处的父元素不局限于document 中) |
update | 不论被绑定的值是否发生了变化,在更新时都会被调用 |
componentUpdated | 被绑定的元素在模板完成一次更新周期时调用 |
unbind | 只调用一次,元素解绑时调用 |
以上所有的钩子函数中都包括了以下参数:
参数 | 说明 |
---|---|
el | 指令所绑定的真实DOM元素,可以直接用来操作DOM |
binding | 一个对象,包含以下属性:name : 指令的名称value : 指令绑定的值oldValue : 指令绑定前一个值expression : 绑定值的字符串形式arg : 传给指令的参数modifiers : 包含修饰符的对象 |
vnode | Vue 编译生成的虚拟节点 |
oldVnode | 上一个虚拟节点,仅在update 和componentUpdated 钩子中可用 |
注意:除了el
之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的dataset
来进行。
具体用法如下所示:
<div v-自定义名称="demo1"></div>
// 写法一:全局指令
Vue.directive("自定义名称", {
bind(el, binding, vnode, oldVnode) { },
inserted(el, binding, vnode, oldVnode) { },
update(el, binding, vnode, oldVnode) { },
componentUpdated(el, binding, vnode, oldVnode) { },
unbind(el, binding, vnode, oldVnode) { },
})
// 写法二:模版下指令
new Vue({
el: '#app',
data: {
demo1: "这是一个demo"
},
directives: {
自定义名称: {
bind(el, binding, vnode, oldVnode) { },
inserted(el, binding, vnode, oldVnode) { },
update(el, binding, vnode, oldVnode) { },
componentUpdated(el, binding, vnode, oldVnode) { },
unbind(el, binding, vnode, oldVnode) { },
}
}
})
下面是一个自定义指令的样例:
<div id="app">
<div v-demo:a.b.c="message"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: "这是一个demo"
},
directives: {
demo: {
bind(el, binding, vnode, oldVnode) {
console.log("el:", el);
console.log("binding:", binding);
console.log("vnode:", vnode);
console.log("oldVnode:", oldVnode);
}
}
}
})
</script>
首先是el
的输出,el
是一个真实的DOM元素:
下面是binding
的输出,arg
是传给指令的参数,expression
是自定义指令=
后面的字符串,modifiers
是包含修饰符的对象,name
是我们给指令起的名字,rawName
是我们写的指令形式,value
是我们给指令传递的值:
下面是vnode
输出:
下面是oldVnode
的输出:
如果我们为指令起的名字很长,需要将很多单词拼接在一起,这时并不会使用小驼峰命名,而是使用-
连在一起即可,形式如下:
<div v-my-demo="message"></div>
这时在directives
中,my-demo
应该写成字符串的形式,具体如下:
// 写法一
Vue.directive("my-demo", { })
// 写法二
directives: {
"my-demo": {
...
}
}
示例代码:
<div id="app">
<div v-my-demo="message"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: "这是一个demo"
},
directives: {
"my-demo": {
bind(el, bindling) {
console.log(bindling);
}
}
}
})
</script>
可以看到name
的值为my-demo
:
在很多时候,我们的bind
和update
会触发相同行为,而且不关心其它的钩子,这时我们可以这样写:
// 写法一
Vue.directive('自定义名称', function (el, binding) { })
// 写法二
new Vue({
...
directives: {
"自定义名称": function (el, binding) { }
}
})
示例:自定义一个v-big
指令,使传入的数字,放大10倍后显示在页面上
<div id="app">
<div v-big="number"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
number: 10
},
directives: {
big: function (el, binding) {
el.innerText = binding.value * 10;
}
}
})
</script>