关于Vue自定义指令的一些讨论(实现v-show效果)
平时学习时做个记录,也分享给大家,各位大佬觉得不好的地方希望指正
- 局部自定义组件的定义
钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<button @click="btn">点击显示隐藏</button>
<h1 v-demo="flag">这是一个标题</h1>
</div>
<script>
new Vue({
el: "#app",
data: {
flag: true
},
methods: {
btn() {
this.flag = !this.flag
}
},
//局部自定义的指令通过directives进行定义
directives: {
//directives里面第一个对象就是我们的自定义组件的名称,比如这里就是demo
demo: {
//demo里面可以有三个钩子函数,一般我们平时用的话就如下两个用的多,以上有对三个钩子函数的官网释义
inserted(el, binding) {
//钩子函数它可以有4个形参,在下面也给大家贴出了官网释义4个参数分别是什么
if (binding.value == true) {
el.style.display = "block"
} else {
el.style.display = "none"
}
},
// 进行状态更新
update(el, binding) {
if (binding.value == true) {
el.style.display = "block"
} else {
el.style.display = "none"
}
}
}
}
})
</script>
</body>
</html>
钩子函数参数
el:指令所绑定的元素,可以用来直接操作 DOM。
binding:一个对象,包含以下 property:
- 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 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
- 全局自定义指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<button @click="btn">点击显示隐藏</button>
<h1 v-demo="flag">这是一个标题</h1>
</div>
<script>
//全局自定义指令通过directive来定义,局部自定义组件是使用directives,注意区分
Vue.directive("demo",{
//这里注释掉inserted是因为学习过程中做了个小测试,下面进行分享
// inserted(el,binding){
// if(binding.value==true){
// el.style.display="block"
// }else{
// el.style.display="none"
// }
// },
// 进行状态更新
update(el,binding){
if(binding.value==true){
el.style.display="block"
}else{
el.style.display="none"
}
}
})
new Vue({
el:"#app",
data:{
flag:false
},
methods:{
btn(){
this.flag = !this.flag
}
}
})
</script>
</body>
</html>
- 关于inserted钩子函数
下面给大家分享一下以上为什么会有想法把inserted这个钩子函数注销进行测试:
因为在学习过程中大家有想法说,我把inserted钩子函数删除,只用update钩子函数也可以实现相同的效果,那么是否真的是这样呢?
我们先看写inserted钩子函数运行后的结果以及dom结构
- 运行结果
- dom结构
我们可以看到inserted写上效果是完全没有问题的
下面是不写inserted钩子函数并且flag为true的运行结果以及dom结构 - 运行结果
- dom结构
我们会发现运行结果都是相同的,但是样式发生了改变,但是为什么会依然能实现呢?
再进行对比,这次是我们上面代码,也就是不写inserted钩子函数并且flag为false的情况 - 运行结果
- dom结构
好了,两个问题出现了,我们明明定义的是false对不对,那为什么刚运行他就是显示的呢?
为什么我们第一次点击没有效果,第二次点击功能就正常了呢?
其实问题很简单,我们前面第一种情况会显示是很正常的,因为项目刚运行的时候,我们的inserted就进行了插入,所以不管我们flag是false还是true都会执行处相应的结果,第二种情况我们就发现了问题,我们没有写inserted钩子函数,但是功能正常,这个时候我们注意到的dom结构上好像少了点什么,带着问题走进第三种情况,样式依旧没有,但是除了一个小问题,第一次点击没有效果,问题就处在了inserted钩子函数身上,我们刚运行事,代码从上往下执行,并没有读取到inserted钩子函数,继续往下读遇到了update钩子函数,这个时候update是不会执行的,因为update只会在发生改变的时候进行更新,而这里我们并没有改变,也就是说刚执行时,我们的自定义指令并没有生效,h1标签也是一个正常显示的状态,这里也就可以解释为什么flag为false时依然会显示,而当我们点击时,flag的状态发生了改变,第二种情况本身flag为true,并且h1本来就是显示的,所以点击后update进行了更新,所以功能正常,但是第三种情况,我们本身就是显示的,自定义指令并没有生效,flag为false,点击之后进行了更新,自定义指令生效了,但是他flag这个时候为true,所以我们第一次点击没有效果,也就可以解释的通了,当我们继续点击的时候功能也就不会有问题了。
总结:inserted会在代码一执行就会把状态加上,如果不写,我们刚进去的时候状态不会有,也就是自定义指令不会生效
初次写博客,不当之处还请各位大佬指正