手把手教你写一个vue自定义loading指令
昨天猛然发现 vue自定义指令 挺好玩的,可以实现很多效果,话不多,咱们开始吧, 2020.4.27更新:发现一个bug存在,当页面有好多个axios请求是,每次请求都会触发componentUpdated这个方法,就会导致页面出现好多个加载框。
使用背景
官网介绍说:有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。其实我觉得吧,用于页面展示的情况会比较多,只有你想不到,没有它做不到。
先来个小demo
// 注册一个全局自定义指令 `v-mydirective`
Vue.directive('mydirective', {
bind: function (el) {
// 可以进行一些逻辑操作
console.log(el)
}
})
//写好这个js后在main.js中引用,然后在页面上绑定一个元素
钩子函数
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
参数
关于参数,常用的有三个,
el:指令所绑定的元素,可以用来直接操作 DOM ,如果你要操作input的值,那么你需要el.addEventListener('input',(e)=>{ el.value = '12';})
binding:一个对象,包含以下属性:
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 编译生成的虚拟节点。它包含有些你所绑定元素的属性。
ps:这些概念性的东西来源于vue的 官方文档,哈哈哈
到这里就差不多介绍完了vue的自定义指令,下面开始我们的主题,自己写一个loading指令
/**
* 其实写这个指令挺简单的,要绑定一个boolean的值,当它为true的时候就往HTML代码里插入一个div,
*然后在这个div里写好加载*样式,当它的值为false时,就把这个div给删除掉
*/
let oldValue = null
Vue.directive('myload', {
// 当被绑定的元素插入到 DOM 中时……
4.21更新:
bind: function (el,binding) {
oldValue = binding.value
if (binding.value) {
//始终设置只有一个加载中弹窗
let myLoadBg = document.getElementById("my-load-bg");
if (myLoadBg) {
myLoadBg.parentNode.removeChild(myLoadBg)
}
let div = document.createElement("div");
div.setAttribute("id", "my-load-bg");
div.innerHTML = "<div class='load-box'>加载中</div>";//你也可以去网上找一些酷炫的加载效果放进去,哈哈哈
document.body.appendChild(div);
}else{
let myLoadBg = document.getElementById("my-load-bg");
myLoadBg.parentNode.removeChild(myLoadBg)
}
},
componentUpdated(el, binding){
if(oldValue != binding.value){
if (binding.value) {
//始终设置只有一个加载中弹窗
let myLoadBg = document.getElementById("my-load-bg");
if (myLoadBg) {
myLoadBg.parentNode.removeChild(myLoadBg)
}
let div = document.createElement("div");
div.setAttribute("id", "my-load-bg");
div.innerHTML = "<div class='load-box'>加载中</div>";
document.body.appendChild(div);
}else{
let myLoadBg = document.getElementById("my-load-bg");
myLoadBg.parentNode.removeChild(myLoadBg)
}
}
}
})
然后在main.js里引入
在页面上用的时候 v-myload="true/false"就可以啦,
第一次写这么长文章,可能写的不太好,嘿嘿