全局变量
最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..');
}
})