在Vue.js應用中,可能須要引入Lodash,Moment,Axios,Async等很是好用的JavaScript庫。當項目變得複雜龐大,一般會將代碼進行模塊化拆分。可能還須要跑在不一樣的環境下,好比瀏覽器,服務端。vue
如何在各個模塊和組件文件中引入須要的庫呢? 找到一種簡單靠譜的方式,能夠省去不少的麻煩。ios
錯誤示範
全局變量法
最不靠譜的方式就是將導入的庫掛在所有變量window
對象下:axios
entry.js瀏覽器
window._ = require('lodash');
MyComponent.vuedom
export default { created() { console.log(_.isEmpty() ? 'Lodash everywhere!' : 'Uh oh..'); } }
這種方式的缺點有不少,咱們只說其中一個關鍵的點:不支持服務端渲染。當應用跑在服務端時,window
對象不存在,固然試圖去訪問window
下的屬性會拋出錯誤。模塊化
到處引入法
另一個不太優雅的方式就是在須要的每一個文件中都引入對應的庫:函數
MyComponent.vueui
import _ from 'lodash'; export default { created() { console.log(_.isEmpty() ? 'Lodash is available here!' : 'Uh oh..'); } }
雖然這方法是可行的,可是太不簡潔。你必須在每一個文件中都記得引入, 並且若是不須要了,又得從新刪除。另外,若是打包策略不夠明智的話,可能會打包出多份重複的代碼。this
正確引入方式
最簡單靠譜的方式是用庫變成Vue
的原型對象的屬性。下面,我來演示如何將Moment庫引入:url
entry.js
import moment from 'moment'; Object.defineProperty(Vue.prototype, '$moment', { value: moment });
因爲全部的組件都會繼承Vue
原型對象上的方法,所以這些方法在任何組件文件中都能經過this.$moment
訪問到:
MyNewComponent.vue
export default { created() { console.log('The time is ' . this.$moment().format("HH:mm")); } }
咱們來仔細看一下其中的原理。
Object.defineProperty
一般咱們會以下設置對象屬性:
Vue.prototype.$moment = moment;
你也能夠這麼作,可是Object.defineProperty
容許咱們用屬性描述器來定義咱們的屬性。咱們能夠定義該屬性是否可寫,可枚舉,可配置。
通常狀況下,咱們不須要用那麼複雜的方式來賦值屬性。但這裏用它有個好處:用屬性描述器定義的屬性是默認只讀的。
這能防止那些腦子不清醒的開發者(極可能是你哦~~)犯下一些低級錯誤:
this.$http = 'Assign some random thing to the instance method'; this.$http.get('/'); // TypeError: this.$http.get is not a function
Object.defineProperty
能保護引入的庫不被從新賦值,若是你嘗試重寫,程序會拋出「TypeError: Cannot assign to read only property」的錯誤。
$
可能你注意到,咱們用「$」開頭的屬性來存放引入的庫。固然,你應該記得還有其餘的一些屬性也是這樣的,好比$refs
, $on
, $mount
。
這種作法不是強制的,這個前綴就是爲了提醒某些昏昏沉沉的開發者(怎麼又是你?!),這些屬性是公有的,你能夠在任何地方使用。反之,某些屬性只能在Vue內部使用。
做爲一門以原型爲基本的語言,JavaScript中並無真正的類,因此也就沒有所謂的公有,私有變量,或者靜態方法。上面這種約定,我以爲是種不錯的選擇。
this
如今你能用this.$libraryName
的方式來訪問你須要的庫了。但,你得保證this
的指向。若是你在回調函數中使用this
,一般這個this
再也不指向Vue實例。
箭頭函數是解決這個問題的好方法。
this.$http.get('/').then(res => { if (res.status !== 200) { this.$http.get('/') // etc // Only works in a fat arrow callback. } });
寫成插件
若是你在項目的不少地方都用了某個庫,或者你但願全局可用,你能夠構建本身的Vue插件。
插件能化繁爲簡,能讓你像下面這樣很簡單地引入本身想要的庫:
import MyLibraryPlugin from 'my-library-plugin'; Vue.use(MyLibraryPlugin);
就像Vue Route,Vuex等插件同樣,咱們的庫僅僅須要兩行,就能在任何地方使用了。
如何寫插件
首先,建立一個文件。本例中,我將引入一個Axios庫的插件。咱們就把這個文件命名爲axios.js
吧。
最關鍵的地方在於,咱們須要暴露一個將Vue構造器做爲第一個參數的install
方法。
axios.js
export default { install: function(Vue) { // Do stuff } }
而後咱們能夠用以前的方式將庫添加到Vue的原型對象上:
axios.js
import axios from 'axios'; export default { install: function(Vue) { Object.defineProperty(Vue.prototype, '$http', { value: axios }); } }
接着咱們只須要Vue實例的use
方法就能將這個庫引入整個項目了。咱們像下面代碼同樣簡單引入:
entry.js
import AxiosPlugin from './axios.js'; Vue.use(AxiosPlugin); new Vue({ created() { console.log(this.$http ? 'Axios works!' : 'Uh oh..'); } })
插件參數設置
插件的install
方法還能夠接受其餘的可選參數。有些開發者可能不喜歡Axios實例對象的方法名$http
,由於Vue resource插件的方法名也是這個。而後,讓咱們利用第二個參數來修改它。
axios.js
import axios from 'axios'; export default { install: function(Vue, name = '$http') { Object.defineProperty(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..'); } })
固然上面,咱們能夠直接在Object.defineProperty
的中將name
屬性寫死成$axios
。也能夠在install
方法中引入多個須要的庫。
轉載:https://blog.csdn.net/fen747042796/article/details/70660419