vue插件编写与实战

前言

热爱vue开发的同学肯定知道awesome-vue 这个github地址,里面包含了数以千计的vue开源插件,而这些插件大都来自第三方开发者们,是他们为vue社区提供了大量的技术支持和解决方案。本文立足vue开源的理念,主要为vue开发者讲解编写vue插件的方法和步骤,通过理论与实践相结合的方式来加深大家对vue插件编写的认识。

vue插件介绍

1. 插件与组件

在讲解插件之前,我们首先来了解下vue插件和组件的关系,在我们的vue项目中我们使用组件的频率往往会大于插件,关系如下图所示:

插件与组件

在没有封装组件之前,如果不使用第三方插件,那么很多情况下我们会编写几个常用的组件来提供给页面使用,如Alert/Loading组件,而你可能需要在很多页面中引入并且通过components注册组件,但是像这样使用率很高的组件一般我们希望全局注册后直接就可以在相应页面使用,因此我们需要将他们封装成插件,比如像vux这样的ui组件库,即提供了组件功能也提供了某些全局注册的插件。

用一句话简单概括两者的关系就是:插件可以封装组件,组件可以暴露数据给插件。

2. 插件分类

插件分类

vue插件的编写方法一般分为4类,如上图所示。主要注册与绑定机制如下:

export default {
    install(Vue, options) {
        Vue.myGlobalMethod = function () {  // 1. 添加全局方法或属性,如:  vue-custom-element
            // 逻辑...
        }

        Vue.directive('my-directive', {  // 2. 添加全局资源:指令/过滤器/过渡等,如 vue-touch
            bind (el, binding, vnode, oldVnode) {
                // 逻辑...
            }
            ...
        })

        Vue.mixin({
            created: function () {  // 3. 通过全局 mixin方法添加一些组件选项,如: vuex
                // 逻辑...
            }
            ...
        })    

        Vue.prototype.$myMethod = function (options) {  // 4. 添加实例方法,通过把它们添加到 Vue.prototype 上实现
            // 逻辑...
        }
    }
}

上方代码使用了es6部分语法列出了4种编写插件的方法,而install是注册插件主要调用的方法,包含了两个参数(Vue实例和自定义配置属性options),我们可以将以上代码存储到plugins.js中。

3. 插件使用

在plugins.js中我们仅仅编写了一个插件的空壳子,假如现在需要全局注册该插件,我们可以在入口文件,比如main.js中注册:

...

import Vue from 'vue'
import MyPlugin from './plugins/plugins.js'

Vue.use(MyPlugin);

...

通过全局方法 Vue.use() 即可使用该插件,其自动会调用install方法。Vue.use会自动阻止注册相同插件多次,届时只会注册一次该插件。

vue插件编写方法

上述我们提到了编写插件的4种方法,接下来我们对其一一进行讲解:

1. 添加全局方法或属性

export default {
    install(Vue, options) {
        Vue.testFun = function () {
      alert('dd')
    }
    }
}

在install方法中,我们直接在Vue实例上声明了$myName属性并进行了赋值,当该插件注册后只要存在Vue实例的地方你都可以获取到Vue.testFun(),因为其直接绑定在了Vue实例上。

2. 添加全局资源

export default {
    install(Vue, options) {
        Vue.directive('focus', {
        //只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
 bind: function() {},
            // 当绑定元素插入到 DOM 中。被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
            inserted: function(el, binding, vnode, oldVnode) {

                // 聚焦元素
                el.focus();
            },
//所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 
            update: function() {},
//指令所在组件的 VNode 及其子 VNode 全部更新后调用。
            componentUpdated: function() {},
//只调用一次,指令与元素解绑时调用
            unbind: function() {}
        });
    },
}

添加全局资源包含了添加全局的指令/过滤器/过渡等,上方代码我们通过Vue.directive()添加了一个全局指令v-focus,其主要包含了5种方法,其中inserted代表当绑定元素插入到 DOM 中执行,而el.focus()代表聚焦绑定的元素,这样如果我们在一个input输入框上绑定该指令就会自动进行focus聚焦。

其他directive提供的方法及用途可以参考:vue自定义指令

3. 添加全局mixin方法

export default {
    install(Vue, options) {
        Vue.mixin({
            methods: {
                greetingFn() {
                    console.log('greeting');
                }
            }
        });
    },
}

mixin代表混合的意思,我们可以全局注册一个混合,其会影响注册之后创建的每个 Vue 实例,上方代码注册后会在每个组件实例中添加greetingFn方法,在单文件组件中可以直接通过this.greetingFn()调用。当然如果实例中存在同名方法,则mixin方法中创建的会被覆盖,同时mixin对象中的钩子将在组件自身钩子之前调用。

4. 添加实例方法

export default {
    install(Vue, options) {
       Vue.prototype.apiCofig = {
      urls: {},
      auth: {}
    }
    },
}

添加实例方法是最常用的一种方法,其直接绑定在vue的原型链上,我们可以回想一下 JS 里的类的概念。实例方法可以在组件内部,通过this.apiCofig 来调用。

5. 插件封装组件

上方4点只讲解了插件自身的4中编写方法,并没有涉及组件的内容,如果我们要在组件的基础上编写插件,我们可以使用Vue.extend(component)来进行,可以见下方loading插件实例。

loading插件

<!-- loading.vue组件 -->
<template>
    <div class="loading-box" v-show="show">
        <div class="loading-mask"></div>
        <div class="loading-content">
            <div class="animate">
            </div>
            <div class="text">{{text}}</div>
        </div>
    </div>
</template>

<script>
export default {
    props: {
        show: Boolean,
        text: {
          type: String,
          default: '正在加载中...'
        },
    }
}
</script>

以上是一个loading.vue组件,省略了样式部分,在没有封装插件之前,我们只能通过import引入并注册到components对象中才能在页面中使用,如:

<template>
<div v-show="Loadshow">
  <div class="loadding">
    <div class="loading">
      <span></span>
      <span></span>
      <span></span>
      <span></span>
      <span></span>
    </div>
  </div>
</div>
</template>

<script>
export default {
  name: 'loadding',
  props: ['Loadshow']
}
</script>

<style lang="scss" scoped>
.loadding{
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  display: flex;
  background-color: rgba(0,0,0,0.5);
  -webkit-justify-content:center;
  justify-content:center;
  -moz-box-pack:center;
  -webkit--moz-box-pack:center;
  box-pack:center;
  align-items:center;
  -webkit-align-items:center;
  box-align:center;
  -moz-box-align:center;
  -webkit-box-align:center;
  z-index: 1111;
  .loading{
    width: 150px;
    height: 15px;
    margin: 0 auto;
    margin-top:100px;
  }
  .loading span{
    display: inline-block;
    width: 15px;
    height: 100%;
    margin-right: 5px;
    border-radius: 50%;
    background: lightgreen;
    -webkit-animation: load 1.04s ease infinite;
  }
  .loading span:last-child{
    margin-right: 0px;
  }
  @-webkit-keyframes load{
    0%{
      opacity: 1;
      -webkit-transform: scale(1.3);
    }
    100%{
      opacity: 0.2;
      -webkit-transform: scale(.3);
    }
  }
  .loading span:nth-child(1){
    -webkit-animation-delay:0.13s;
  }
  .loading span:nth-child(2){
    -webkit-animation-delay:0.26s;
  }
  .loading span:nth-child(3){
    -webkit-animation-delay:0.39s;
  }
  .loading span:nth-child(4){
    -webkit-animation-delay:0.52s;
  }
  .loading span:nth-child(5){
    -webkit-animation-delay:0.65s;
  }
}
</style>

下面我们便来封装一下该组件:

import loaddingCon from '../components/common/loadding.vue'
/**
 * [说明]
 * @file: service.js
 * @flow: 【声明插件】——【写插件】——【注册插件】——【使用插件】
 * @author: JCY
 */
let $vue
export default {
  install: function (Vue, options) {
    // 将添加的内容写在该函数内
    debugger
    if (!$vue) {
      const LoadPlugin = Vue.extend(loaddingCon)
      $vue = new LoadPlugin({
        el: document.createElement('div')
      })
      document.body.appendChild($vue.$el)
      $vue.Loadshow = false
      let loadding = {
        show () {
          $vue.Loadshow = true
        },
        hide () {
          $vue.Loadshow = false
        }
      }
      if (!Vue.loadding) {
        Vue.loadding = loadding
      }
      Vue.mixin({
        created () {
          this.laddingspan = Vue.loadding
        }
      })
    }
    debugger
    // 1. 添加全局方法或属性
    Vue.prototype.apiCofig = {
      urls: {},
      auth: {}
    }
  }
}

以上我们新建一个loading.js文件,引入我们的loading.vue组件,然后通过Vue.extend()方法创建了一个构造器LoadPlugin

,其次我们再通过new LoadPlugin()创建了$vue实例,并挂载到一个div元素上。最后我们需要通过document.body.appendChild($vue.$el)将其插入到DOM节点中。

当我们创建了$vue实例后,我们可以访问该实例的属性和方法,比如通过$vue.show就可以改变loading组件的show值来控制其显示隐藏。

最终我们通过Vue.mixin或者Vue.prototype.$loading来全局添加了$loading事件,其又包含了show和hide两个方法。我们可以直接在页面中使用this.laddingspan.show()来显示加载,使用this.laddingspan..hide()来关闭加载。

效果:

 

 

插件发布

插件编写完后我们的目的除了本地引用注册外,可能更希望发布到线上供他人或其他项目使用,因此我们需要了解插件发布的方法。

1. 发布准备

在发布插件前你需要一个npm账号,你可以访问:https://www.npmjs.com/ 进行注册

2. 发布命令

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值