一 第三方JavaScript庫
前言
.vue文件 中不解析 script標簽引入js文件,只能用 import 引入
有兩種用法:
1.import a from '../a'
2.import '../a'
區別在於第一個你要用到export導出之后 才能用import導入。
第二個是直接引入 和script標簽是一樣的. 但是它作用在自己的js文件中。
在使用vue做項目的時候,我們一般不將css樣式寫到各自的組件里,這樣不僅會讓代碼冗余,而且不美觀整潔。如果你定義了一些外部css文件,如何引入到vue組件中去呢?我們這里使用ES6的引入方式:
<template></template>
<style scoped>
@import "../assets/common/common.css";
</style>
那么JS文件如何引入呢?如果需要全局使用,則可以在main.js中引用並實例化對象:
部分js代碼:
const DEBUG = true;
let BASE_URL = DEBUG ? 'url' : '';
const API = {
//網關設備管理
'edgeManager':{
'deviceList':BASE_URL + '/devicemanager/device/list.do',//網關設備列表
'deviceDelete':BASE_URL + '/devicemanager/device/delete.do'//網關設備刪除
}
}
export default API;
在main.js中:
import API from './assets/api/api.config.js'
Vue.prototype.$API = API;
這樣,我們在vue組件中使用this.$API
就可以找到這個js文件中的對象了。
如:this.$API.edgeManager.deviceList
如果需要按需引入,不在main.js中引入,直接在有需要的vue組件中引入:
部分代碼:
<template></template>
<script>
import API from '../../assets/api/api.config.js'
</script>
這樣引入的話,我們在當前組件可以直接使用API去找到這個js文件中的對象。
如:API.edgeManager.deviceList
需要注意的是,第二種方式按需引入的js文件在其他組件中是找不到這個對象的。
在Vue.js應用中,可能需要引入Lodash,Moment,Axios,Async等非常好用的JavaScript庫。
當項目變得復雜龐大,通常會將代碼進行模塊化拆分。可能還需要跑在不同的環境下,比如瀏覽器,服務端。
如何在各個模塊和組件文件中引入需要的庫呢? 找到一種簡單靠譜的方式,可以省去很多的麻煩。
----------------錯誤示范----------------
全局變量法
最不靠譜的方式就是將導入的庫掛在全部變量window對象下:
entry.js
window._ = require('lodash');
MyComponent.vue
export default {
created() {
console.log(_.isEmpty() ? 'Lodash everywhere!' : 'Uh oh..');
}
}
這種方式的缺點有很多,我們只說其中一個關鍵的點:不支持服務端渲染。當應用跑在服務端時,window對象不存在,當然試圖去訪問window下的屬性會拋出錯誤。
處處引入法
另外一個不太優雅的方式就是在需要的每個文件中都引入對應的庫:
MyComponent.vue
import _ from 'lodash';
export default {
created() {
console.log(_.isEmpty() ? 'Lodash is available here!' : 'Uh oh..');
}
}
雖然這方法是可行的,但是太不簡潔。你必須在每個文件中都記得引入, 而且如果不需要了,又得重新刪除。另外,如果打包策略不夠明智的話,可能會打包出多份重復的代碼。
-----------正確引入方式-----------
最簡單靠譜的方式是用庫變成Vue的原型對象的屬性。下面,我來演示如何將Moment庫引入:
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插件
如果你在項目的很多地方都用了某個庫,或者你希望全局可用,你可以構建自己的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方法中引入多個需要的庫。