读万卷书行万里路

vue plugin 插件编写以loading为例

发布时间:2017/11/24 10:30:20
分类:frontend/vue
    全文约973
    预计需要4分钟

我们在使用vue开发的过程中,经常会遇到这两个问题:

我要使用loading(加载动画) toast(浮层提示) dialog(弹框提示)之类的全局性组件,但是用全局组件注册的话非常麻烦,还要在template标签中书写组件html代码然后参数通过在data选项中注册变量来控制组件的显示/隐藏/提示语,显得异常麻烦~
我要使用某些全局函数例如(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 &#123;
    data() &#123;
      return &#123;
        isShow: false,
        hasAnimate: true,
      &#125;
    &#125;,
    computed: &#123;
      /**
       * 动画效果样式,没有返回空
       * @return &#123;String&#125; 样式
       */
      animateName() &#123;
        return this.hasAnimate ? 'opacity' : ''
      &#125;,
    &#125;,
    methods: &#123;
      /**
       * 开启动画效果
       */
      opemAnimate() &#123;
        this.hasAnimate = true
      &#125;,
      /**
       * 去除动画效果
       * @return &#123;Promise&#125; 返回promise
       */
      removeAnimate() &#123;
        return new Promise((resolve) => &#123;
          this.hasAnimate = false
          resolve()
        &#125;)
      &#125;,
      /**
       * 显示动画loading
       */
      show() &#123;
        this.isShow = true
      &#125;,
      /**
       * 隐藏动画loading
       */
      hide() &#123;
        this.isShow = false
      &#125;,
    &#125;,
  &#125;
</script>

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

  .loadings &#123;
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background: transparent;

    &__loader &#123;
      position absolute
      top 50%
      left 50%
      transform translate3d(-50%,-50%,0)

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

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

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

  .opacity &#123;
    &-enter-active, &-leave-active &#123;
      transition: all 0.6s
    &#125;
    &-enter, &-leave-active &#123;
      opacity: 0
    &#125;
  &#125;
</style>

这时如果你将其注册为全局组件,也是可以使用的,但是前面我们说过,这样使用非常不优雅

然后我们将其做成插件

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

export default &#123;
  /**
   * 每个插件都有的install方法,用于安装插件
   * @param &#123;Object&#125; Vue - Vue类
   * @param &#123;Object&#125; [pluginOptions] - 插件安装配置
   */
  install(Vue, pluginOptions = &#123;&#125;) &#123;
    // 创建"子类"方便挂载
    const VueLoading = Vue.extend(Loading)
    let loading = null

    /**
     * 初始化并显示loading
     * @returns &#123;Promise&#125; Promise实例
     */
    function $loading() &#123;
      return new Promise((resolve) => &#123;
        // 第一次调用
        if (!loading) &#123;
          loading = new VueLoading()
          // 手动创建一个未挂载的实例
          loading.$mount()
          // 挂载
          document.querySelector(pluginOptions.container || 'body').appendChild(loading.$el)
        &#125;
        // 显示loading
        loading.show()
        resolve()
      &#125;)
    &#125;
    // 定义关闭loading方法
    $loading.end = (noAnimate = false) => &#123;
      return new Promise((resolve) => &#123;
        if (!loading || !loading.isShow) &#123;
          resolve()
          return
        &#125;
        // 首页判断是否在关闭时需要动画
        if (noAnimate) &#123;
          // 默认只在此次行为下移除动画,之后的行为仍有动画
          loading.removeAnimate().then(() => &#123;
            loading.opemAnimate()
          &#125;)
        &#125;

        loading.hide()
      &#125;)
    &#125;

    Vue.loading = Vue.prototype.$loading = $loading
  &#125;,
&#125;

然后我们在入口文件app.js中引入并且安装插件就可以了:

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

···
Vue.use(VueLoading, &#123;
  container: '.app',
&#125;)
···

接下来可以在你任意想要的地方执行this.loading()就可以启动loading动画了,在需要关闭的地方执行this.loading.end()就可以关闭咯

目录
文章作者:CavinHuang
文章链接:http://blog.zukmb.cn/posts/d11faa5b/
版权声明:转载请注明来自CavinHuangのBlog
Linux创建用户只能访问某个目录
Request —— 让 Node.js http请求变得超简单