说明
不好意思经过了这么久时间才开始继续写文章,确实懒散了很久。废话不多说,开始本文吧。
正文
本篇是在阅读v-loading时产生的部分感悟,因此独立出来作为一篇文章讲解一下。
本篇主要给大家介绍一下vue的自定义指令directive
,以及我们如何通过directive
将一个组件插入到代码当中,并控制显隐。
directive
官网链接。官网中已经介绍了directive
。我们可以发现, 注册一个自定义指令的时候,它会包含以下几个钩子函数。bind
、inserted
、update
、componentUpdated
。
其中
bind
只执行一次,即在指令绑定到元素的时候执行
inserted
会在元素插入到父元素的时候执行
update
会在所插入的组件发生变化的时候发生改变
componentUpdated
所在组件的 VNode 更新时调用
注意注意
这里的update
的执行并不是只在绑定的值发生改变的时候执行, 比如说在一个div
中插入v-loading=change
。
当div
所在的模板<template>
中有元素发生改变的时候,此时无论是否涉及到我们的绑定元素update
都会执行。
并且componentUpdated
也会执行。
每个钩子函数都会传入以下几个参数
el
、bind
、vnode
、oldVnode
。
el
是绑定的dom元素,可以直接操作dom
bind
则包含指令的多个元素:name
,value
,oldValue
。。。(先了解这三个即可,我们可以通过value和oldValue的对比来判断绑定指令是否发生改变,以此判断是否要执行update
。
vnode
,vue的虚拟节点
oldVnode
,上一个虚拟节点。
插入组件
现在我们来说一说如何插入组件,在这里我们要用到以下几个api, extend
、$mount
,
extend
: 接收一个组件选项作为参数,创建一个子类。
比如我们有一个loading
的模板
<template>
<div class="loading" v-show="showLoading">
。。。
</div>
</template>
<script>
export default {
name: 'loading',
data () {
return {
showLoading: false,
}
}
}
</script>
<style lang="scss" scoped>
@import '@/components/scss/mixins.scss';
@import './style.scss';
</style>
复制代码
我们可以创建一个index.js
文件,并在其中实例化一个loading
对象
import Vue from 'vue'
import loading from './app.vue';
const LoadingConstructor = Vue.extend(loading);
复制代码
那么我们如何将loading
组件实例化并插入到指定元素下面呢?
export default {
install (Vue) {
// extend vue基础构造器, 创建一个包含组件的对象
const LoadingConstructor = Vue.extend(loading);
// 创建自定义指令 v-loading
Vue.directive('v-loading', {
bind: function(el) {
console.warn('执行bind');
// 实例化一个loading对象
el.loading = new LoadingConstructor();
// 将loading的挂载实例加载在el下
el.appendChild(el.loading.$mount().$el);
},
inserted: function() {
console.warn('执行insterted');
},
// 发生在所绑定的模版更新的时候, 即<template>的更新时候发生
update: function(el, bind) {
console.warn(el);
if (bind.value !== bind.oldValue) {
el.loading.showLoading = bind.value;
}
console.warn('执行update');
},
componentUpdated: function() {
console.warn('执行componentUpdated');
},
})
}
}
复制代码
关于这段代码,其中可能有疑问应该是这一句 el.appendChild(el.loading.$mount().$el);
,这句是将loading
的实例挂载在父元素el
之下, 如果我们这样写
const loading = new LoadingConstructor();
loading.$mount(el);
复制代码
那么元素el将会被loading实例所取代, 因此我们要将loading实例挂载在el之下,就需要el.appendChild(loading组件)。 loading.el即是loading组件。
(果然,长久时间不写,生疏了不少,各位看官见谅)。