vue2.0插件--loading


  loading效果很常見,常見到我們任何一個項目中,都可以見到他的身影。今天就以loading作為切入口,嘮叨一下vuejs的插件的寫法。

  看vuejs官方文檔關於插件的說明,關於使用插件和寫插件,Vue插件基本上都躲不開以下幾種方案: 

  1. 添加全局方法或者屬性,如: vue-custom-element

  2. 添加全局資源:指令/過濾器/過渡等,如 vue-touch

  3. 通過全局 mixin 方法添加一些組件選項,如: vue-router

  4. 添加 Vue 實例方法,通過把它們添加到 Vue.prototype 上實現。

  5. 一個庫,提供自己的 API,同時提供上面提到的一個或多個功能,如 vue-router

  我們以loading效果為例,添加一個全局自定義指令的方式寫一個插件。使用方式如: 

<div v-loading="loading"></div>

  依賴loading值,展示或者隱藏loading效果。loading值默認為false,不展示loading效果。

  loading效果的模板其實很簡單,甚至可以用唯一一個div標簽完成,這里我們不強求怎么寫loading模板,我們將模板定義在Loading.vue文件內。

  在loading.js文件內真正寫插件:

  首先看一下Vue.use這個方法:

安裝 Vue.js 插件。如果插件是一個對象,必須提供 install 方法。如果插件是一個函數,它會被作為 install 方法。install 方法調用時,會將 Vue 作為參數傳入。

  也就是說我們在loading.js文件中export一個對象出去的時候,如果該對象是普通的對象,則需要在對象中添加一個install的方法,而如果導出一個函數對象,可以直接導出該函數。

  就以當前的loading舉例說明:

  如果導出一個對象:

export default {
  vm: null,
  install: Vue => {
    Vue.directive(Loading.name, {
      // 真正的實現邏輯
    })
  },
  ...
}

  而如果導出是一個函數,我們可以這么寫:

export default Vue => {
  Vue.directive(Loading.name, {
    // 真正的實現邏輯
  })
}

  仔細觀察一下,發現我們可以將install方法的函數體直接導出當做use的參數。

  我們這里就以對象方式導出,主要目的是留一個vm屬性,用於保存生成的loading節點,方便刪除該節點。

  在剛剛寫這個插件的時候,不是插件不會寫,恰恰是自定義指令的鈎子函數使用不當,導致問題的產生。我們需要依賴指令的binding.value值來展示或者隱藏loading效果。基本上嘗試了所有的鈎子函數后,發現只有update是在所在的組件 VNode 更新時調用,也就是說binding.value的值發生變化,在update內部更新dom。

update (el, binding) {
  const ele = window.getComputedStyle(el, null)
  // 添加判斷,如果當前元素的高度小於60 則loading固定在整個屏幕中間 否則固定在當前元素中間
  LoadingComp.vm.$el.style.position = !binding.modifiers.fixed && (parseInt(ele['height']) < 60 ? 'fixed' : 'absolute')
  binding.value ? el.appendChild(LoadingComp.vm.$el) : el.removeChild(LoadingComp.vm.$el)
}

  需要稍作解釋的時候,我們有時候綁定的v-loading的dom節點高度在完全沒有數據的時候,可能完全沒有高度可言,那么這里就將loading的position設置為fixed,固定在屏幕中央。這里可以自行定義是否需要該判斷條件。

 binding.value ? el.appendChild(LoadingComp.vm.$el) : el.removeChild(LoadingComp.vm.$el)

  這么一句,就是添加和刪除當前的loading節點,有點類似於v-if的處理效果。

  這里還缺少生成loading的DOM節點這一過程,是因為我認為其他的過程只要生成一次就可以了,而不會隨着binding.value的值變化發生任何變化。所以需要在鈎子函數inserted內實現: 

inserted (el, binding) {
  const elem = window.getComputedStyle(el, null)
  el.style.position = elem['position'] === 'static' && 'relative'
  LoadingComp.vm = new LoadingConstructor().$mount()
  // 如果帶修飾符fixed loading固定在屏幕中間
  let val = binding.modifiers.fixed && 'fixed'
  LoadingComp.vm.$el.style.position = val && val
}

  主要實現的是,當前綁定v-loading的元素是否有定位,如果沒有定位屬性,則添加position:"relative"屬性。並同時生成loading對象,注意這里僅僅是生成,並沒有掛載到文檔中。

  添加的一行注釋,主要多實現了一個功能,就是如果用戶就非得相對整個屏幕固定loading,那么可以使用v-loading.fixed="loading"來達成這一效果。

  這里其實可以引申出來,如果loading需要遮罩層的效果的話,也可以以類似的方法實現。

  看看完整的代碼吧!

import Vue from 'vue'
import Loading from './Loading.vue'
const LoadingConstructor = Vue.extend(Loading)
const LoadingComp = {
  vm: null,
  install: Vue => {
    Vue.directive(Loading.name, {
      inserted (el, binding) {
        const elem = window.getComputedStyle(el, null)
        el.style.position = elem['position'] === 'static' && 'relative'
        LoadingComp.vm = new LoadingConstructor().$mount()
        // 如果帶修飾符fixed loading固定在屏幕中間
        let val = binding.modifiers.fixed && 'fixed'
        LoadingComp.vm.$el.style.position = val && val
      },
      update (el, binding) {
        const ele = window.getComputedStyle(el, null)
        // 添加判斷,如果當前元素的高度小於60 則loading固定在整個屏幕中間 否則固定在當前元素中間
        LoadingComp.vm.$el.style.position = !binding.modifiers.fixed && (parseInt(ele['height']) < 60 ? 'fixed' : 'absolute')
        binding.value ? el.appendChild(LoadingComp.vm.$el) : el.removeChild(LoadingComp.vm.$el)
      }
    })
  }
}

export default LoadingComp

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM