意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

探索vue自定义指令的玄妙

来源:恒创科技 编辑:恒创科技编辑部
2024-02-03 13:40:59


自定义指令的语法

Vue自定义指令语法如下:

Vue.directive(id, definition)

传入的两个参数,​​id​​​是指指令ID,​​definition​​是指定义对象。其中,定义对象可以提供一些钩子函数:


探索vue自定义指令的玄妙

钩子函数

定义对象的钩子函数如下:

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​​ 钩子函数。

所以一个指令的定义,无非就是在合适的钩子函数中编写一些相关的处理逻辑。


上一篇: 你该知道的浏览器请求与Header 下一篇: 手机怎么远程登录云服务器?