想必用過 element-ui 來開發中後臺項目的同窗都知道,其內置的 v-loading 指令是很是友好,只須要提供一個 Boolean 值就能實現加載動畫的一個指令,若是使用過 element-ui,但沒有使用過 v-loading 指令的同窗,不妨先了解一下基本用法vue
本文會經過 源碼剖析、思路分析以及簡單實現三個步驟,來簡單呈現其實現的原理。node
首先打開 element-ui 項目目錄,定位到 v-loading 主文件git
import directive from './src/directive'; // loading指令實現
import service from './src/index'; // loading服務方式實現
export default {
install(Vue) {
Vue.use(directive);
Vue.prototype.$loading = service;
},
directive,
service
};
複製代碼
此文件對外暴露了三個屬性,分別是 install函數、directive指令實現以及service服務方式實現github
此文件會被 element組件入口文件 引入, 而且把 directive指令 全局註冊了一遍以及在 Vue
原型上擴展了 $loading
方法element-ui
// line 156
Vue.use(Loading.directive);
// line 163
Vue.prototype.$loading = Loading.service;
複製代碼
Vue.js 的插件應該有一個公開方法 install
。這個方法的第一個參數是 Vue 構造器,第二個參數是一個可選的選項對象:bash
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或屬性
Vue.myGlobalMethod = function () {
// 邏輯...
}
// 2. 添加全局資源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 邏輯...
}
...
})
// 3. 注入組件
Vue.mixin({
created: function () {
// 邏輯...
}
...
})
// 4. 添加實例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 邏輯...
}
}
複製代碼
其實 v-loading
實現思路很簡單,且聽我一一道來。app
Vue.directive
內置了五個鉤子函數 bind(綁定觸發)
、inserted(插入觸發)
、update(更新觸發)
、componentUpdated(組件更新觸發)
和unbind(解綁觸發)
函數
當須要綁定 v-loading
生成好後,咱們能夠根據綁定的 Boolean 值,來控制顯隱動畫
那麼如何生成loading效果遮罩層呢?element-ui的作法是 利用Vue.extend擴展loading組件,實時計算其樣式值,而且把擴展的實例掛載到鉤子函數的el參數中,以達到改變組件狀態的目的ui
接下來我將簡單實現一遍 v-loading
的核心功能,來幫助你們更好的掌握
首先,咱們須要定義一個 loading
組件:
<template>
<transition name="loading-fade">
<div
v-show="visible"
class="loading-mask"
>
loading
</div>
</transition>
</template>
<script>
export default {
name: 'Loading',
data() {
return {
visible: false
};
}
};
</script>
複製代碼
注意看這裏 visible
,這個屬性就是來控制整個loading組件顯隱的
當咱們指令綁定以後,就須要對綁定的 value
值進行監聽
import Vue from 'vue';
import Loading from './loading';
// Loading構造函數
const Mask = Vue.extend(Loading);
const loadingDirective = {};
loadingDirective.install = Vue => {
// 切換組件狀態函數
const toggleLoading = (el, binding) => {
if (binding.value) {
Vue.nextTick(() => {
insertDom(el, el, binding);
});
}
else {
el.instance.visible = false;
}
};
// 插入Loading
const insertDom = (parent, el) => {
parent.appendChild(el.mask);
el.instance.visible = true;
};
Vue.directive('loading', {
bind: function(el, binding) {
/**
* 這裏把Loading組件實例掛載到el上,而後再把el傳參到toggleLoading中判斷
*/
const mask = new Mask({
el: document.createElement('div'),
data: {}
});
el.instance = mask;
el.mask = mask.$el;
el.maskStyle = {};
binding.value && toggleLoading(el, binding);
},
update: function(el, binding) {
if (binding.oldValue !== binding.value) {
toggleLoading(el, binding);
}
},
unbind: function() {
// destory
}
});
};
export default loadingDirective;
複製代碼
Loading 指令
的具體實如今此 文件