我想大家都接触过 v-on、v-show 等等指令,那自定义指令是什么呢?自定义指令就是你现在所想的那样,自己写一个自定义指令去操作 DOM 元素,以达到代码复用的目的。一提到代码复用,我想大家都能想到组件,这里要注意的是自定义指令和组件的适用范围是不一样的。组件一般是我们复用一个结构、一个样式、一个逻辑。而自定义指令是当我们想对 dom 进行底层操作,而且底层操作是一样功能的时候,这时就可以使用自定义指令了。
注册指令分为全局注册和局部注册
全局注册:
Vue.directive('focus', {/** */})
复制代码
局部注册:
const vm = new Vue({ el: '#app', directives: { focus: {/** */} }})
复制代码
例:写一个自动聚焦输入框的指令 v-focus
<body> <div id="app"> <input type="text" v-focus> </div>
<script> //定义全局指令 Vue.directive("focus",{ inserted(el){ el.focus() } }) //定义局部指定 const vm = new Vue({ el: "#app", data: {}, directives: { focus: { inserted(el) { el.focus(); }, }, }, </script></body>
复制代码
但凡有 input 框需要自动聚焦,直接加上v-focus就可以了。
☛注意:当全局指令和局部指令名字冲突的时候,会使用局部指令,所以在自定义指令的时候,要么全局,要么局部,二选一。
实现结果:
自定义指令生命周期钩子函数
接下来详细说明自定义指令配置对象,配置对象里面的东西并没有那么难,都是一些钩子函数,执行到某些时刻就执行的函数,也可以叫自定义指令生命周期钩子函数。
当把指令绑定到 dom 元素身上的时候就会执行,由于只绑定一次,所以只执行一次,在这里可以进行一次性的初始化设置。
inserted 被绑定的元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)
update 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
componentUpdated 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind 指令与 dom 元素解绑时调用(被绑定的 Dom 元素被 Vue 移除),只调用一次。
钩子函数的参数
el:指令所绑定的元素,可以用来直接操作 DOM
binding:对象,包含以下属性:
name : 指令名,不包括 v-前缀
value :指令的绑定值,例如:v-focus="1+1"中,绑定值为 2.
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可以使用。
expression:字符串形式的指令表达式。例如,v-focus="1+1",表达式为"1+1"
arg : 传给指令的参数,可选。例如,v-focus:src 中,参数为"src"
modifiers:一个包含修饰符的对象。例如,v-focus.obj.nice 中,修饰符对象为{obj: true, nice: true}
vnode:Vue 编译生成的虚拟节点。
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用
模拟 v-show 指令
<body> <div id="app"> <input type="text" v-myshow="show" /> </div>
<script> //模拟show指令 Vue.directive("myshow", { bind(el, binding) { const { value } = binding; const display = value ? "" : "none"; el.style.display = display; }, update(el,binding) { const { value } = binding; const display = value ? "" :"none"; el.style.display = display; }, });
const vm = new Vue({ el: "#app", data: { show: true, }, }); </script> </body>
复制代码
结果演示:
如果在 bind 和 update 中触发相同的行为,而不关心其它钩子函数时,可以写成函数的形式,如下:
<body> <div id="app"> <input type="text" v-myshow="show" /> </div>
<script> //模拟show指令 Vue.directive("myshow",(el,binding)=>{ const { value } = binding; const display = value ? "" : "none"; el.style.display = display; });
const vm = new Vue({ el: "#app", data: { show: true, }, }); </script> </body>
复制代码
模拟 v-modle 指令
<body> <div id="app"> <input type="text" v-mymodel="content" />{{ content }} </div>
<script> //模拟v-model指令 Vue.directive("mymodel",{ bind(el,binding,vnode){ const vm= vnode.context; const {value,expression} = binding; el.value = binding.value el.oninput = function(){ const inputValue = el.value; vm[expression] = inputValue; } }, update(el,binding){ const {value} = binding; el.value = value } })
const vm = new Vue({ el: "#app", data: { content:"法医" }, }); </script> </body>
复制代码
结果演示:
评论