Vue的插件开发

331 阅读3分钟

一、写在前面

插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:

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

  2. 添加全局资源:指令/过滤器/过渡等。如 vue-touch

  3. 通过全局混入来添加一些组件选项。如 vue-router

  4. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。

  5. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象。

二、 Vue.prototype 实现

通过Vue.prototype来把方法添加到实例上面。

非插件开发

//myplugin.js

import Vue from "vue"

Vue.prototype.$myplugin = function(){}
函数或属性
Vue.prototype.$myplugin = {}

有几个问题:

   1. import Vue from "vue" 中的 vue 是自定义的,用户自己配置的,可能和你的这个 vue 不是一个

   2. $myplugin可能被用户自己占用

开发插件:

// myplugin.js

var myplugin = {};
myplugin.install = function (Vue, options) {
    Vue.prototype.$myplugin = function(){};
}
exports default myplugin;

// main.js
import Vue from 'vue';
import myplugin from './myplugin.js';
Vue.use(myplugin);

Vue.use(myplugin)  安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。 该方法需要在调用 new Vue() 之前被调用。 当 install 方法被同一个插件多次调用,插件将只会被安装一次。

之后我们就可以通过 this.$myplugin 来使用插件了

插件开发好处在于,由用户自己调用use,这样用户的Vue版本和插件没有关系

三、添加全局方法或者属性

// myplugin.js

var myplugin = {};
myplugin.install = function (Vue, options) {
    Vue.$myplugin = function(){};
}
exports default myplugin;

和添加实例方法类似

四、directive 添加全局指令

指令钩子函数

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性初始化设置
  • inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
  • update:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。指令值可能发生了变化,也可能没有发生变华。
  • componentUpdated:指令所在组件的VNode及子VNode全部更新后调用
  • unbind:只调用一次,指令与元素解绑时调用

钩子函数参数

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作DOM
  • binding:一个对象,包含以下属性
    • name:指令名,不包含v-前缀
    • value:指令的绑定值,例如:v-my-direactive= "1+1"中表达式值为2
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1"中,表达式为 "1 + 1"
  • arg:传给指令的参数,可选。例如 v-my-directive:foo中,参数为 foo
  • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }

指令开发

// myplugin.js

var myplugin = {};
Toast.install = function (Vue, options) {
  Vue.directive("time", {
    bind(el, binding) {
     el.innerHTML = el.innerHTML ? el.innerHTML : el.textContent;
     el.innerHTML = Time.getFormatTime(binding.value);
}
exports default myplugin;

import myplugin from 'myplugin'
Vue.use(time);

五、全局混入开发

// 定义一个混入对象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

// 定义一个使用混入对象的组件
var Component = Vue.extend({
  mixins: [myMixin]
})

var component = new Component() // => "hello from mixin!"

Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

new Vue({
  myOption: 'hello!'
})
// => "hello!"

vm.$options用于当前 Vue 实例的初始化选项。需要在选项中包含自定义 property 时会有用处

六、插件开发,动态生成组件

import Toast from "./toast";

//toastplugin.js

export default {
  install(Vue, options) {
    Vue.prototype.$toast = function(message) {
      let Constructor = Vue.extend(Toast);
      let toast = new Constructor();
      toast.$slots.default = [message];
      toast.$mount();
      document.body.appendChild(toast.$el);
    };
  }
};

//app.js  

methods:{
    toast(){
      this.$toast("toast!!!")
    }
  }

//index.js

import Vue from "vue";
import toastplugin from "./toast/toastplugin";
Vue.use(toastplugin);

样式在toast.vue 中写

为什么我要动态生成?,因为我的toast组件不会写在app.vue里面,需要点击才出现