探索vue自定义指令的玄妙
Posted 恪愚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了探索vue自定义指令的玄妙相关的知识,希望对你有一定的参考价值。
自定义指令的语法
Vue自定义指令语法如下:
Vue.directive(id, definition)
传入的两个参数,id
是指指令ID,definition
是指定义对象。其中,定义对象可以提供一些钩子函数:
钩子函数
定义对象的钩子函数如下:
- bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作
- inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)
- update:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新
- componentUpdate:被绑定元素所在模板完成一次更新周期时调用
- unbind:只调用一次,指令与元素解绑时使用
在钩子函数中,还有一些参数可供选择:
参数 | 描述 |
---|---|
el | 指令所绑定的元素,可以直接操作Dom |
binding | 指令的描述对象 |
arg | 传给指令的参数,可选。例如 v-transfer:f40="{id:item.id,name:'mxc'}" ,在指令中可通过:binding.value.id/name 获取(这时 arg 就是 f40 ) |
vnode | Vue 编译生成的虚拟节点 |
oldVnode | 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用 |
而在binding中,还有几个属性:
- name: 指令名,不包括
v-
前缀 - value: 指令的绑定值。例如:
v-my-directive=”1 + 1”
,value 的值是 2。 - oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- expression:字符串形式的指令表达式。例如
v-my-directive="1 + 1"
中,表达式为 “1 + 1”
简单使用
Vue自定义指令常见使用例子如下:
Vue.directive('my-directive', {
bind: function(){
//做绑定的准备工作
//比如添加事件监听器,或是其他只需要执行一次的复杂操作
},
inserted: function(){
//...
},
update: function(){
//根据获得的新值执行对应的更新
//对于初始值也会调用一次
},
componentUpdated: function(){
//...
},
unbind: function(){
//做清理操作
//比如移除bind时绑定的事件监听器
}
}
当指令的定义对象中只使用update
时,只需直接传入函数即可,如下:
//全局方式
Vue.directive('my-directive', function(){
//...
})
//局部的方式下面的例子就是
自定义指令是怎么和methods关联起来的
像简单的一些自定义指令比如赋值甚至内置的v-focus
来说,使用非常方便,直接在回调中操作即可。
但是如果让你使用自定义指令实现拖拽、触底校验…这类复杂的操作呢?
这是完全有可能的。因为自定义指令的特殊性,我们完全可以用自定义指令做一些小的插件。而插件不可能涵盖所有的场景。
这时候就需要methods中函数(通过v-on
,即@
注册的)的参与了!
实际上,vue中是通过传参的形式,将methods中的函数传进来,以此来改变data中的值。就像这样:
methods:{
set(x,y){
this.data.x=x;
this.data.y=y;
}
},
directives:{
// 拖动的自定义指令
drag(el,binding){
//el为拖动的元素
var oDiv =el;
oDiv.onmousedown = function(e){
e.preventDefault();
e.stopPropagation();
var disX = e.offsetX;
var disY = e.offsetY;
document.onmousemove = function(e){
e.preventDefault();
e.stopPropagation();
var x=e.pageX-disX;
var y=e.pageY-disY
oDiv.style.left=x
oDiv.style.top=y
// 通过传参的形式,将methods中的函数传进来,以此来改变data中的值
binding.value.set(x,y)
};
document.onmouseup = function(){
document.onmousemove=null;
document.onmouseup=null;
};
};
}
},
然后使用:
<div v-drag="{set:set}"></div>
指令的生命周期?
指令本质上是一个javascript对象,对象上挂载着一些钩子函数。
我们可以举个例子来说明:比如笔者定义一个v-log
指令,这个指令做的事情就是在指令的各个生命周期中去输出一些log信息:
const logDirective = {
beforeMount() {
console.log('log directive before mount')
},
mounted() {
console.log('log directive mounted')
},
beforeUpdate() {
console.log('log directive before update')
},
updated() {
console.log('log directive updated')
},
beforeUnmount() {
console.log('log directive beforeUnmount')
},
unmounted() {
console.log('log directive unmounted')
}
}
然后你可以以全局指令 方式在创建应用后注册它:
import { createApp } from 'vue';
import App from './App';
const app=createApp(App);
app.directive('log',logDirective);
app.mount('#app');
使用上也很方便:
<template>
<input v-if="flag" v-log v-model="text"/>
<button @click="flag=!flag">toggle</button>
</template>
<script>
export default {
data() {
return {
flag: true,
text: ''
}
}
}
</script>
当你点击按钮后,会先执行指令定义的 beforeMount
和 mounted
钩子函数,然后你在 input 输入框中输入一些内容,会执行 beforeUpdate
和 updated
钩子函数,然后你再次点击按钮,会执行 beforeUnmount
和 unmounted
钩子函数。
所以一个指令的定义,无非就是在合适的钩子函数中编写一些相关的处理逻辑。
以上是关于探索vue自定义指令的玄妙的主要内容,如果未能解决你的问题,请参考以下文章