VNode
前面讲到了自定义指令的引入使用,以及结合封装swiper组件一起进行结合使用,还记在inserted 指令生命周期当中使用的参数吗?第一个参数是可以拿到DOM节点(el),第二个参数是可以拿到使用自定义指令绑定的值(binding),那么它还有第三个参数,就是本篇内容要讲的这个 VNode ,那么当听到这个虚拟DOM,VNode,虚拟节点 和 vdom这些词其实指的是 在Vue中虚拟DOM其实是一个js对象来模拟真实DOM节点跟 diff 算法搭配方便做比对,最后Vue会进行哪些节点能否被复用的复用,不能复用的删除创建,以此达到更好的用户体验。那么下面来简单的自定义一个指令来使用这个三个参数:
<div id="app">
<div v-custom = "'customVal'">
{{mytext}}
</div>
</div>
<script>
Vue.directive("custom",{
inserted(el,binding,vnode){
console.log(el);
console.log(binding.value);
console.log(vnode);
}
})
new Vue({
el:'#app',
data:{mytext:'自定义指令'}
})
</script>
可以查看一下VNode的内容其实它是一个虚拟DOM,虚拟DOM的内容相对真实DOM的内容要少一些,虚拟DOM当中仅有一些必要的属性,那么下面创建一个空div遍历一下真实的DOM:
回头看一下这个VNode,当中没有设置key值,所以可以看到的是key值是undefined值;
在这个div当中还有一个子节点 " {{mytext}} ",没有 "tag",所以它是一个普通的文本节点;
VNode.context
那么看这些和拿到这个虚拟DOM有啥用?我们知道在Vue中实例化创建之后 —— 才有状态 —— 再有VNode —— 映射真实DOM ,所以这个 VNode 起到关联索引的作用,如果放置在根节点,它就是根组件,放置在里边就是一个子组件,在VNode当中有一个context属性,它能关联到当前组件所在节点的对象,VNode.context 拿到的是组件对象,如果放置在根组件的话,拿到的就是Vue的实例;
拿到Vue实例有什么用?还记在上一篇内容当中,在inserted指令生命周期中去拿swiperList的数组长度吗?this.swiperList.length并不能够拿到,this的指向是window对象,我们是通过指令绑定的一个对象,通过这个对象的传过来的,那么现在通过VNode.context能够拿到Vue根组件的实例,不就轻而易举的就访问到根组件中swiperList的数组长度;下面来更改上一回封装swiper获取swiperList.length的方式:(具体内容看上一篇内容)
上一篇部分代码:(this指向)
<!-- v-swiper绑定的是对象 -->
...
<div v-swiper=" { current : index , length : swiperList.length } "> ... </div>
..
<script>
Vue.diretive("swiper",{
inserted(el,binding){
// 通过 binding.value.length 拿到 swiperList.length
console.log(binding.value.length); // 输出3
}
})
new Vue({ el:'#app',data:{ swiperList:[] },mounted(){ // 赋值swiperList数组三条数据 } })
<script>
修改代码:
<!-- v-swiper绑定的是对象 -->
...
<div v-swiper="index"> ... </div>
..
<script>
Vue.diretive("swiper",{
inserted(el,binding,vnode){
// 通过 vnode.context
console.log(vnode.context.swiperList.length); // 输出3
}
})
new Vue({ el:'#app',data:{ swiperList:[] },mounted(){ // 赋值swiperList数组三条数据 } })
<script>
当然如果是封装的话还是需要注意这个,虽然通过vnode.context可以拿到swiperList.length,但它内部是非常依赖外部的状态,如果使用者用到不是swiperList存放数据的话,通过vnode.content.swiperList.length 具有强关联和强耦合,自己使用的话无可厚非。
小知识 - 指令相关周期
常用的 inserted 和 update ,如果内容相同,可以使用函数(function)进行简写;
bind : 只调用一次,指令第一次绑定到元素时调用,在这里可以进行一次性的初始化设置;
inserted : 被绑定元素插入父节点时调用(仅能保证父节点存在,但不一定已被插入到文档中);
update : 所有组件的VNode更行时调用,但是可能发生发生在其子VNode更新之前.指令的值可能发生了改变,也可能没有,但是通过比较更新前后的值来忽略不必要的模板更新;
componentUpdated : 指令所在组件的VNode及其子VNode(children)全部更新后调用;
upbind : 只调用一次,指令与元素解绑时调用;
那么本篇的内容就到此结束,感谢大家的支持!