全局變量
將 JavaScript 第三方庫 添加到項目中,最簡單的辦法是通過將其附加到window對象上,以使其成為全局變量:
JavaScript代碼:
// entry.js 文件
window._=require('lodash');
JavaScript代碼:
// MyComponent.vue 文件
exportdefault{
created(){
console.log(_.isEmpty()?'Lodash everywhere!':'Uh oh..');
}
}
這種情況會使window變量不斷增長,但是最關(guān)鍵的是,他們不能使用服務(wù)器渲染。當應(yīng)用程序在服務(wù)端運行時,window對象是undefined的,因此嘗試訪問window下的屬性將會拋出一個錯誤。
在每個文件中導(dǎo)入
另一種二流的方法是將庫導(dǎo)入到每個文件中:
JavaScript代碼:
// MyComponent.vue 文件
import_from'lodash';
exportdefault{
created(){
console.log(_.isEmpty()?'Lodash is available here!':'Uh oh..');
}
}
這是有效的,但是你需要重復(fù)手動導(dǎo)入和移除,這是一個痛點:你必須記住將這個庫導(dǎo)入到每個文件中,然后當你的某個文件不用這個庫的時候, 記得要將它從這個文件中移除。如果你沒有正確地設(shè)置你的構(gòu)建工具,則可能會最終導(dǎo)致在構(gòu)建包中存在同一個庫的多個副本。
一個更好的方式
在Vue項目中使用Javascript庫的最干凈,最健壯的方法是將其代理為 Vue 原型對象的屬性。我們用這種方式,將 Moment日期和時間庫添加到我們的項目中:
JavaScript代碼:
// entry.js 文件
importmomentfrom'moment';
Object.definePrototype(Vue.prototype,'$moment',{value:moment});
由于所有組件都會繼承 Vue 原型對象上方法,這將使 Moment 自動可用于任何組件,沒有全局變量或任何需要手動導(dǎo)入的組件。它可以在任何 實例/組件 中簡單地通過this.$moment訪問被訪問:
JavaScript代碼:
// MyComponent.vue 文件
exportdefault{
created(){
console.log('The time is '.this.$moment().format("HH:mm"));
}
}
現(xiàn)在讓我們花點時間了解一下這是如何工作的。
Object.defineProperty
我們通常會像這樣設(shè)置一個對象屬性:
JavaScript代碼:
Vue.prototype.$moment=moment;
你可以這么做,但是通過使用Object.defineProperty,我們可以使用描述符來定義我們的屬性。描述符允許我們設(shè)置一些低級細節(jié),例如我們的屬性是否可寫,以及在for循環(huán)中枚舉期間是否顯示。
我們通常不會在日常使用 Javascript 中使用到描述符,因為 99% 的時間我們不需要這么細致的屬性分配。但這里給我們一個明顯的優(yōu)勢:默認情況下,使用描述符創(chuàng)建的屬性是只讀的。
這意味著,一些糊涂的開發(fā)人員(可能是你)不能在組件內(nèi)去做一些很愚蠢的事情, 并且破壞一切.
JavaScript代碼:
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等等也都是以”$”開頭。
雖然屬性名上添加前綴不是必須的,但是這樣做可以提醒糊涂的開發(fā)人員(可能是你),這是一個公共API屬性或方法,歡迎你使用,不像其他屬性的實例,可能只是為了 Vue 的內(nèi)部使用。
作為基于原型的語言,Javascript 中沒有(真正的)類,因此也沒有 “私有” 和 “公共” 變量或 “靜態(tài)” 方法。 這個慣例是一種很好的替代品,我們認為是值得遵守的約定。
this
你還會注意到,你可以使用this.libraryName來使用這個庫 ,但是這樣做會有個小小的問題,因為它現(xiàn)在是一個實例方法。
然而,這樣做的結(jié)果是,與全局變量不同,您在使用庫時必須確保處于正確的作用域中。內(nèi)部的回調(diào)方法不能通過this來訪問你的庫。
幸好,ES6中的箭頭函數(shù)是一個不錯的解決方案, 它能確保你在正確的作用域中:
JavaScript代碼:
// script.js
this.$http.get('/').then(res=>{
if(res.status!==200){
this.$http.get('/')// etc
// 只在箭頭回調(diào)函數(shù)中起作用。愚人碼頭注:你也可以使用ES5 的 bind();
}
});
為什么不使它成為一個插件?
如果您打算在多個 Vue 項目中使用 JavaScript 第三方庫,或者您想與世界分享你的庫,您可以將其構(gòu)建成插件!
插件提取復(fù)雜性的部分,允許你在項目中簡單地執(zhí)行以下操作來添加你選擇的庫:
JavaScript代碼:
// script.js
importMyLibraryPluginfrom'my-library-plugin';
Vue.use(MyLibraryPlugin);
使用這兩行,我們可以在任何組件中使用 JavaScript 第三方庫,就像我們可以使用 Vue Router ,Vuex 和其他使用 Vue.use 的插件一樣。
編寫一個插件
首先,為您的插件創(chuàng)建一個文件。在這個例子中,我將創(chuàng)建一個插件,將 Axios 添加到你所有的 Vue 實例和組件中,因此我將調(diào)用文件axios.js。
要了解的主要內(nèi)容是:插件必須公開一個install方法,并且將 Vue 構(gòu)造函數(shù)作為第一個參數(shù):
JavaScript代碼:
// axios.js
exportdefault{
install:function(Vue){
// Do stuff
}
}
現(xiàn)在我們可以使用之前介紹的方法將庫添加到原型對象中:
JavaScript代碼:
// axios.js
importaxiosfrom'axios';
exportdefault{
install:function(Vue,){
Object.defineProperty(Vue.prototype,'$http',{value:axios});
}
}
我們現(xiàn)在需要做的事情是use實例方法將我們的庫添加到一個項目。例如,我們現(xiàn)在可以輕松地添加 Axios 庫:
JavaScript代碼:
// entry.js
importAxiosPluginfrom'./axios.js';
Vue.use(AxiosPlugin);
newVue({
created(){
console.log(this.$http?'Axios works!':'Uh oh..');
}
})
彩蛋: 插件可選參數(shù)
你插件里的install方法允許接受可選參數(shù)。 一些開發(fā)人員可能不是很喜歡使用 axios 實例的方法名$http,因為 Vue Resource 已經(jīng)使用了這個名字,所以讓我們使用一個可選參數(shù)來讓它們變成你所喜歡的方法名:
JavaScript代碼:
// axios.js
importaxiosfrom'axios';
exportdefault{
install:function(Vue,name='$http'){
Object.defineProperty(Vue.prototype,name,{value:axios});
}
}
JavaScript代碼:
// entry.js
importAxiosPluginfrom'./axios.js';
Vue.use(AxiosPlugin,'$axios');
newVue({
created(){
console.log(this.$axios?'Axios works!':'Uh oh..');
}
})