Vue 中使用第三方库的方法

在 Vuejs 项目中使用 JavaScript 库,可以每个文件里面分别import,但是太繁琐也不利于后期维护。有一个优雅方式是将其代理到 Vue 的原型对象上去。

银弹就是 Object.defineProperty

举个栗子:

例如引入 axios 库:

import axios from 'axios';
Vue.prototype.$ajax = axios;

使用的时候,this.$ajax.post(),很方便。再来一个 moment 库,这个也是使用较多的一个:

import moment from 'moment';
Object.defineProperty(Vue.prototype, '$moment', { value: moment });

使用的时候,this.$moment()

工作原理:

Object.defineProperty

一般而言, 可以按照下面的方式来给对象设置属性:

Vue.prototype.$moment = moment;

可以这样做, 但是 Object.defineProperty 允许我们通过一个 descriptor 来定义属性。Descriptor 运行我们去设置对象属性的一些底层(low-level)细节, 如是否允许属性可写? 是否允许属性在 for 循环中被遍历。

通常, 我们不会为此感到困扰, 因为大部分时候, 对于属性赋值, 我们不需要考虑这样的细节。但这有一个明显的优点: 通过 descriptor 创建的属性默认是只读的。

这就意味着, 一些处于迷糊状态的(coffee-deprived)开发者不能在组件内去做一些很愚蠢的事情, 就像这样:

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 的错误.

$

你可能会注意到, 代理第三库的属性会有一个 $ 前缀, 也可能看到其它类似 $refs, $on, $mount 的属性和方式, 它们也有这个前缀.

这个不是强制要求, 给属性添加 $ 前缀是提供那些处于迷糊状态(coffee-deprived)的开发者这是一个公开的 API, 和 Vuejs 的一些内部属性和方法区分开来.

this

你还可能注意到, 在组件内是通过 this.libraryName 的方式来使用第三方库的, 当你知道它是一个实例方法时就不会感到意外了. 但与全局变量不同, 通过 this 来使用第三方库时, 必须确保 this 处于正确的作用域. 在回调方法中 this 的作用域会有不同, 但箭头式回调风格能保证 this 的作用域是正确的:

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

感谢下面两位作者:

英文:Use Any Javascript Library With Vue.js

译文:如何在 Vue.js 中使用第三方库