[译]在vuejs中使用任意js库

原文

全局变量

最naive的办法是通过附加类库到window对象,使之成为全局变量:

entry.js

window._ = require('lodash');

MyComponent.vue

export default {
    created() {
        console.log(_.isEmpty() ? 'Lodash everywhere!' : 'Un oh..');
    }
}

这个办法不好的是,当app运行在服务端的时候就糟糕了,我们会发现抛出了一个异常:window对象没有定义。

每个文件都导入

MyComponent.vue

import _ from 'lodash';

export default {
    created() {
        console.log(_.isEmpty() ? 'Lodash is available here!' : 'Uh oh..');
    }
}

这个方法违背了DRY原则。你必须在每个要使用lodash的文件中都import。

推荐的做法

最聪明的做法是将类库作为Vue prototype对象的一个属性:

entry.js

import moment from 'moment';

Object.definePrototype(Vue.prototype, '$moment', { value: moment });

MyNewComponent.vue

export default {
    created() {
        console.log('The time is '+ this.$moment().format('HH:mm'));
    }
}

现在我们花点时间来看看它是如何工作的。

Object.definePrototype

通常我们这样设置一个对象的属性:

Vue.prototype.$moment = moment;

你可以像上面一样做。但是使用Object.definePrototype,可以定义一个有descriptor的属性。descriptor能让我们设置一些低级别的细节,例如属性是否是可写的,在枚举循环中是否出现。

当然99%的情况我们不需要处理descriptor的低级别的细节。但是使用它有一个好处:使用descriptor定义的属性默认是只读的

这意味不要当心这个属性被别人覆盖了:

this.$http = 'Assign some random thing to the instance method';
this.$http.get('/'); // TypeError: this.$http.get is not a function

只读的属性不会让上面的事情发生,如果有人尝试覆盖只读属性,会得到一个异常:“TypeError: Cannot assign to read only property”。

$

你可能注意到我们代理类库的属性名以$为前缀。

根据约定,$前缀告诉使用者,这个属性是一个公共API的属性或者方法,大家可以使用它。而不是只在Vue内部中使用的属性或方法。

this

this.libraryName告诉我们这个是个实例方法。

这样的话,我们在使用类库的时候要注意要在正确的上下文当中。

箭头函数是一个解决作用域的好办法:

this.$http.get('/').then(res => {
  if (res.status !== 200) {
    this.$http.get('/') // etc
    // Only works in a fat arrow callback.
  }
});

为什么不做成一个插件

如果你计划在多个Vue项目中使用一个类库,你可以将他build为你的一个插件!

使用插件非常简单:

import MyLibraryPlugin from 'my-library-plugin';
Vue.use(MyLibraryPlugin);

写一个插件

首先,为你的插件创建一个文件。在这个例子中我做了一个Axios的插件,可以在任何Vue实例和component中使用axios,因此这个名为axios.js

一个插件最重要的是install方法,它将Vue构造器作为第一个参数:
axios.js:

export default {
    install: function (Vue) {
        // Do stuff
    }
}

现在我们使用上面的方法将类库添加到prototype对象:
axios.js:

import axios from 'axios'

export default {
    install: function (Vue) {
        Object.definePrototype(Vue.prototype, '$http', { value: axios });
    }
}

我们可以如下一样,非常简单的就能使用Axios类库了:
entry.js

import AxiosPlugin from './axios.js'
Vue.use(AxiosPlugin);

new Vue({
    created() {
        console.log(this.$http ? 'Axios works!' : 'Uh oh..');
    }
});

福利:插件的可选参数

插件的install方法接受一个可选的参数。有些开发者可能不喜欢$http这个名字,通过这个可选参数,可以让这些开发者自定义名字:
axios.js:

import axios from 'axios';

export default {
    install: function(Vue, name = '$http') {
        Object.definePrototype(Vue.prototype, name, { value: axios };
    }
}

entry.js

import AxiosPlugin from './axios.js';
Vue.use(AxiosPlugin, '$axios');

new Vue({
  created() {
    console.log(this.$axios ? 'Axios works!' : 'Uh oh..');
  }
})
posted @ 2017-08-08 09:02  irocker  阅读(506)  评论(0编辑  收藏  举报