vue自定义指令
当我们使用插件的时候,有时候会看到插件上使用v-xxx
的用法,例如在使用图片懒加载时,我们可以看到他用了v-lazy的指令,这是怎么做的呢 ?
图片:
这是vue中的自定义指令,Vue-directive
,我们可以使用这个自定义指令来做很多效果,例如数据加载时,显示加载的遮罩,当加载完成后,再把这个遮罩框移除,效果如下:
这样的效果要如何来做呢,根据vue官网上的用法说明来使用就可以
// main.js
Vue.directive('loading',{
}
})
我们可以在main.js中写到Vue.directive('loding',{...})
这里第一个参数是loading
,也就是要传入的指令,如果要自定义一个v-lazy
指令那就写Vue.directive('lazy',{...})
第二个参数我们可以写一个对象,对象中包含以下几种钩子函数,他们分别表示
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind
:只调用一次,指令与元素解绑时调用。
我们这个方法中使用update方法就可以了,让v-loading
的初始值为false,当请求数据的时候将它设为true
,请求数据完成后再设为false
这样v-loading的状态发生了改变,就会触发自定义指令中的update方法
// main.js
Vue.directive('loading',{
update(el,binding,vNode,oldVnode){
}
})
这个方法有4个参数,分别是el
,binding
,vnode,
oldVnode
,将它依次打印出来可以看到这些参数
第一个是绑定的dom元素,第二个参数是一个对象,包含不同的属性,我们在这里可以依据binding.value
来判断v-loading
中绑定的值,当它为true
时,说明正在加载,这时候往body中添加一个遮罩框就可以实现加载中…的效果,当它为false
的时候,加载完成,我们再把它移除就可以了。
- 下面是完整代码
// main.js
Vue.directive('loading',{
update(el,binding,vNode,oldVnode){
console.log(el,binding,vNode,oldVnode)
if(binding.value===true){
let oDiv = document.createElement('div')
oDiv.id = 'loadingWrapper'
oDiv.style = `position:fixed;
background:rgba(0,0,0,.3);top:0;right:0;
bottom:0;left:0;color:#fff;z-index:3000;display:flex;
justify-content:center;align-items:center;`
oDiv.innerHTML = '加载中...'
document.body.appendChild(oDiv)
} else {
document.body.removeChild(document.getElementById('loadingWrapper'))
}
}
})
<template>
<div id="app">
<button @click="getData" v-loading="isLoading">加载数据</button>
<ul>
<li v-for="item in list" :key="item.id">{{item}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return{
list: [],
isLoading: false
}
},
methods:{
getData(){
this.isLoading = true
setTimeout(()=>{
this.list = ['小明,20岁,来自北京','小张,22岁,来自河北','老刘,31岁,来自包头']
this.isLoading = false
},1000)
}
},
}
</script>
<style>
</style>
动态指令参数
到了这里,我们已经完成了指令的使用,如果我们希望自己来定义遮罩的颜色,字体大小,位置等,我们应该怎么做呢,这时候可以借助动态指令参数来完成
v-loading:[argument]
我们可以将原来的代码改写成
// App.vue
<button @click="getData" v-loading[style]="isLoading">加载数据</button>
...省略其他代码...
data(){
return{
style: `position:fixed;z-index:3000;display:flex;
background:rgba(255,0,0,.3);top:0;right:0;
bottom:0;left:0;color:#green;font-size:40px;
justify-content:center;align-items:center;`
}
}
// main.js
Vue.directive('loading',{
update(el,binding,vNode,oldVnode){
console.log(el,binding,vNode,oldVnode)
if(binding.value===true){
console.log('jiazai')
let oDiv = document.createElement('div')
oDiv.id = 'loadingWrapper'
oDiv.style = binding.arg
oDiv.innerHTML = '加载中...'
document.body.appendChild(oDiv)
} else {
document.body.removeChild(document.getElementById('loadingWrapper'))
}
}
})
这时候动态传入指令参数就完成了,遮罩的背景变成了红色,字体变大