vue plugin 插件編寫以loading爲例

我們在使用vue開發的過程中,經常會遇到這兩個問題:

  1. 我要使用loading(加載動畫) toast(浮層提示) dialog(彈框提示)之類的全局性組件,但是用全局組件註冊的話非常麻煩,還要在template標籤中書寫組件html代碼然後參數通過在data選項中註冊變量來控制組件的顯示/隱藏/提示語,顯得異常麻煩~
  2. 我要使用某些全局函數例如(axios)來進行某些操作,如果每次使用都需要import或者require的話,是一件不太優雅的事情

所以我們就想到在vue的全局實例Vue或者指向這個實例的指針this的原型上添加某一方法來達到隨用隨取的效果。

本文以loading爲例,講下如何編寫一個Vue插件。

首先我們編寫一個普通的loading組件,作爲插件的模板:

 // my-project/src/plugin/loading/loading.vue
<template>
  <transition :name="animateName">
    <div class="loadings" v-show="isShow">
      <div class="loadings__loader">
        <div class="loadings__loader__dot"></div>
        <div class="loadings__loader__dot"></div>
        <div class="loadings__loader__dot"></div>
        <div class="loadings__loader__dot"></div>
        <div class="loadings__loader__dot"></div>
      </div>
    </div>
  </transition>
</template>
<script type="text/babel">
  export default {
    data() {
      return {
        isShow: false,
        hasAnimate: true,
      }
    },
    computed: {
      /**
       * 動畫效果樣式,沒有返回空
       * @return {String} 樣式
       */
      animateName() {
        return this.hasAnimate ? 'opacity' : ''
      },
    },
    methods: {
      /**
       * 開啓動畫效果
       */
      opemAnimate() {
        this.hasAnimate = true
      },
      /**
       * 去除動畫效果
       * @return {Promise} 返回promise
       */
      removeAnimate() {
        return new Promise((resolve) => {
          this.hasAnimate = false
          resolve()
        })
      },
      /**
       * 顯示動畫loading
       */
      show() {
        this.isShow = true
      },
      /**
       * 隱藏動畫loading
       */
      hide() {
        this.isShow = false
      },
    },
  }
</script>

<style lang="stylus" rel="stylesheet/stylus" scope>

  .loadings {
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background: transparent;

    &__loader {
      position absolute
      top 50%
      left 50%
      transform translate3d(-50%,-50%,0)

      &__dot {
        width 40px
        height 40px
        background #3ac
        border-radius 100%
        display inline-block
        animation slide 1s infinite
        margin-right: 6px;

        for index in (1..5) {
          &:nth-child({index}) {
            animation-delay (0.2 + 0.1s * index)
            // background green(#ce2424, (50 * index))
            background lighten(#ce2424, (index * 6))
          }
        }
      }
    }
  }

  @keyframes slide
    0%
      transform scale(1)
    50%
      opacity .3
      transform scale(2)
    100%
      transform scale(1)

  .opacity {
    &-enter-active, &-leave-active {
      transition: all 0.6s
    }
    &-enter, &-leave-active {
      opacity: 0
    }
  }
</style>

這時如果你將其註冊爲全局組件,也是可以使用的,但是前面我們說過,這樣使用非常不優雅

然後我們將其做成插件

 // my-project/src/plugin/loading/index.js
import Loading from './loading.vue'

export default {
  /**
   * 每個插件都有的install方法,用於安裝插件
   * @param {Object} Vue - Vue類
   * @param {Object} [pluginOptions] - 插件安裝配置
   */
  install(Vue, pluginOptions = {}) {
    // 創建"子類"方便掛載
    const VueLoading = Vue.extend(Loading)
    let loading = null

    /**
     * 初始化並顯示loading
     * @returns {Promise} Promise實例
     */
    function $loading() {
      return new Promise((resolve) => {
        // 第一次調用
        if (!loading) {
          loading = new VueLoading()
          // 手動創建一個未掛載的實例
          loading.$mount()
          // 掛載
          document.querySelector(pluginOptions.container || 'body').appendChild(loading.$el)
        }
        // 顯示loading
        loading.show()
        resolve()
      })
    }
    // 定義關閉loading方法
    $loading.end = (noAnimate = false) => {
      return new Promise((resolve) => {
        if (!loading || !loading.isShow) {
          resolve()
          return
        }
        // 首頁判斷是否在關閉時需要動畫
        if (noAnimate) {
          // 默認只在此次行爲下移除動畫,之後的行爲仍有動畫
          loading.removeAnimate().then(() => {
            loading.opemAnimate()
          })
        }

        loading.hide()
      })
    }

    Vue.loading = Vue.prototype.$loading = $loading
  },
}

然後我們在入口文件app.js中引入並且安裝插件就可以了:

···
import Vue from 'vue'
import VueLoading from './loading'
···

···
Vue.use(VueLoading, {
  container: '.app',
})
···

接下來可以在你任意想要的地方執行this.loading()loadingthis. loading.end()就可以關閉咯

不信試試~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章