element-ui深刻淺出 v-loading指令

想必用過 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;
複製代碼

Loading 指令實現

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 指令 的具體實如今此 文件

相關文章
相關標籤/搜索