vue自定义指令初探
一、什么是自定义指令
自定义指令是用来操作DOM的。尽管Vue推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅可用于定义任何的DOM操作,并且是可复用的。
在vue中,除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。有的情况下,对普通 DOM 元素进行底层操作,这时候就会用到自定义指令
二、自定义指令的核心知识
自定义指令分为钩子函数和钩子函数的参数
1、钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
我们会在稍后讨论渲染函数时介绍更多 VNodes 的细节。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
接下来我们来看一下钩子函数的参数 (即 el、binding、vnode 和 oldVnode)。
2、钩子函数的参数
指令钩子函数会被传入以下参数:
el:指令所绑定的元素,可以用来直接操作 DOM。 binding:一个对象,包含以下 property: name:指令名,不包括 v- 前缀。 value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。 oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。 expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。 arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。 modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。 vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。 oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
三、动态指令参数
指令的参数可以是动态的。例如,在 v-mydirective:[argument]="value" 中,argument 参数可以根据组件实例数据进行更新!这使得自定义指令可以在应用中被灵活使用。
例如你想要创建一个自定义指令,用来通过固定布局将元素固定在页面上。我们可以像这样创建一个通过指令值来更新竖直位置像素值的自定义指令:
<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'
})
// 这会把该元素固定在距离页面顶部 200 像素的位置。但如果场景是我们需要把元素固定在左侧而不是顶部又该怎么办呢?这时使用动态参数就可以非常方便地根据每个组件实例来进行更新。
四 、vue bind和inserted的详细区别
- 适用
需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令
1.钩子函数参数
除了 el 之外,其它参数都应该是只读的,切勿进行修改
2.动态指令参数
v-mydirective:[argument]=“value”
argument可以是动态变化的,并且在钩子里面实时更新的 4.钩子区别
update 和 componentUpdated
共同点:组件更新都会调用,update在componentUpdated之前
不同点:
update 组件更新前的状态
componentUpdated 组件更新后的状态
场景:点击事件,div的内容追加 !;
update(el, binding,vnode,oldVnode){
console.log(el.innerHTML); // <div>!</div>
}
componentUpdated(el, binding,vnode,oldVnode){
console.log(el.innerHTML); // //<div>!!</div>
}
// 注意: 区别是div里面的!数量
bind 和 inserted
共同点: dom插入都会调用,bind在inserted之前
不同点:
bind 时父节点为 null
inserted 时父节点存在。
bind是在dom树绘制前调用,inserted在dom树绘制后调用
bind: function (el) {
console.log(el.parentNode) // null
console.log('bind')
},
inserted: function (el) {
console.log(el.parentNode) // <div class="directive-box">...</div>
console.log('inserted')
}
五 、演示代码
// 根据条见判断 元素的显示与隐藏
Vue.directive('changeColor', {
inserted:function(el, binding) {
el.style.color = 'red'
el.style.background = '#ccc'
// arg 获取自定义指令的动态参数
console.log("binding1",binding.arg)
if(binding.value < 3) {
el.style.display="none"
}else{
el.style.display="block"
}
},
update:function(el, binding,vnode,oldVnode){
console.log("vnode",vnode,oldVnode)
el.style.color = 'red'
el.style.background = '#ccc'
console.log("binding11",binding)
if(binding.value < 3) {
el.style.display="none"
}else{
el.style.display="block"
}
// 这个自定义指令会影响所有的使用数据
}
})
代码仅供参考,代码不全
// 在很多时候,你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('changeColor',
function(el, binding) {
el.style.color = 'red'
el.style.background = '#ccc'
// arg 获取自定义指令的动态参数
console.log("binding1111111",binding.arg)
if(binding.value < 3) {
el.style.display="none"
}else{
el.style.display="block"
}
// 这个自定义指令会影响所有的使用数据
})
参考文章:https://blog.csdn.net/haduwi/article/details/104949560 vue bind和inserted的详细区别
https://blog.csdn.net/qq_40299179/article/details/80086227
https://cn.vuejs.org/v2/guide/custom-directive.html