想必用过 来开发中后台项目的同学都知道,其内置的 指令是非常友好,只需要提供一个 Boolean 值就能实现加载动画的一个指令,如果使用过 ,但没有使用过 指令的同学,不妨先了解一下基本用法
本文会通过 源码剖析、思路分析以及简单实现三个步骤,来简单呈现其实现的原理。
源码剖析
首先打开 element-ui 项目目录,定位到
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服务方式实现
此文件会被 引入, 并且把 directive指令 全局注册了一遍以及在 Vue
原型上扩展了 $loading
方法
// line 156Vue.use(Loading.directive);// line 163Vue.prototype.$loading = Loading.service;复制代码
Loading 指令实现
Vue.js 的插件应该有一个公开方法 install
。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
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
实现思路很简单,且听我一一道来。
Vue.directive
内置了五个钩子函数 bind(绑定触发)
、inserted(插入触发)
、update(更新触发)
、componentUpdated(组件更新触发)
和unbind(解绑触发)
当需要绑定 v-loading
生成好后,我们可以根据绑定的 Boolean 值,来控制显隐
那么如何生成loading效果遮罩层呢?element-ui的做法是 利用Vue.extend扩展loading组件,实时计算其样式值,并且把扩展的实例挂载到钩子函数的el参数中,以达到改变组件状态的目的
简单实现
接下来我将简单实现一遍 v-loading
的核心功能,来帮助大家更好的掌握
首先,我们需要定义一个 loading
组件:
复制代码 loading
注意看这里 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 指令
的具体实现在此