前情提要
筆者在公司的專案開發上選擇vue作為前端開發framework,不外呼就是開發應用程式,當然免不了基本的CRUD功能,此時需要一個強而有力的呼叫API套件,之所以選擇axios
,沒有爾外的原因,因為是vue作者推薦使用,這樣不需有任何的疑慮,用下去就對了,此篇就以axios
來探討其用法介紹及經驗分享。
使用工具及環境參考[Vue]Vue基本語法
內容
使用方式
我們要在專案上使用第一部就是使用npm
來安裝它
1 | npm install axios |
若要在component上套用axios則,需先import它
1 | import axios from 'axios'; |
接下來我們先來看一下簡單的get指令
1 | // Make a request for a user with a given ID |
建立axios實體
1 | const instance = axios.create({ |
視情況會使用到自己宣告出來的axios實體,筆者遇到的情形是
- 呼叫不同的API站台時
- 需要有獨立的config設定時
alias別名(簡寫)
以上使用到axios
所提供的簡寫功能get
,axios提供我們會常用到http action
的簡寫宣告
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.options(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
Config項目介紹
接下來介紹有哪些config可以設定,先來看一下一般的宣告方式
1 | // Send a POST request |
完整的config項目列表,其中url
為必填之外,其他為選填項目,筆者盡量以自己的理解的方式寫上註解
1 | { |
以上僅列出部份config項目,完整請參考axios github中的說明
全域設定
設定方式
axios
很貼心的提供了全域設定的功能,等於說有些設定是共用的,可以透過defaults
來設定,通常一定會設置一個baseURL
,頁面上的呼叫api設定的url就只要設定相對url即可。
1 | axios.defaults.baseURL = 'https://api.example.com'; |
以上只是很簡單的舉了三個例子,第一個是設定baseURL,第二個是將登入成功後取得的token,設定於每次request中的header參數中,第三個是指定post時的content type為html encode過後的,以防腳本攻擊。這些只是簡單的例子,基本上defaults
後面可以接上述提到的所有config項目。
設定優先順序探討
參考axios
github中的Config order of precedence
- request當中
config
defaults
關鍵字設定之全域設定lib/defaults.js
Interceptor攔截器
使用方式
筆者特別想介紹這個部份,此功能非常重要,我們要做什麼事情,有了這個攔截器,根本就是事半功倍阿。簡單來說就是axios
開放request前或response得到後事件,方便我們撰寫統一處理邏輯。
最簡單的應用就是我們在request的時候,無論是取得下拉式選單的data source,設定條件後按下「查詢」取得相對應的資料,都需要等待時間,現代都是求速成,連一秒都不願意等待,需要馬上有feedback,通常我們都會選擇使用顯示loading
讓使用者知道我們很努力的在獲取資料。
這個時候這個攔截器的好處就浮現了,一般沒有攔截器的情況下,我們必須得在每一個request中必須處理顯示loading
的邏輯,但這樣一來,重複的程式碼出現在不同地方,需要更改效果時根本就是惡夢阿。
1 | // Add a request interceptor |
移除攔截器
我們可以使用interceptor攔截器
,當然也可以移除它
1 | //使用const變數宣告request interceptor |
筆者當初看到這個說明會覺得不會使用到它,直到有些頁面中有autocomplete
功能時,就會用上它了。我們專案的情境是我們會在main.js
中宣告全域的interceptor,每次發出呼叫API的request前先將loading...
畫面顯示,得到response後將其關閉。但問題來了,我們的autocomplete
功能,也是會產生呼叫API的情形,會變成每打一個字會產生loading...
效果,這是我們不希望的。
筆者在上述的問題解決方式採用上面提到的宣告一個新的axios實體
方式,並且將該實體的interceptor設定中使用eject
方式移除特定interceptor,當然在呼叫API時使用該axios實體
1 | // 宣告於main.js中 |
多個請求Concurrency化
axios
有提供多個request平行處理的功能all
,然後可以使用spread
將多個response當作參數接進來
1 | axios.all([ |
實例
我們來做一下實例吧,找一個公開的api jsonplaceholder 串接,並使用interceptor
做進一步的處理。
安裝及設置前置作業
前置作業很多,但我會以這個專案為模版,其他文章的範例會使用這個專案繼續完成其他套件示範。
- 使用
vue-cli
initial webpack模版專案1
vue init webpack DemoApp
- 安裝
bootstrap-vue
接著使用visual studio code
開啟專案,為了版面漂亮,我們來安裝一下bootstrap
吧,為了使用現成的bootstrap component,我們就直接安裝bootstrap-vue
接著我們在1
npm install bootstrap-vue --save
main.js
中bootstrap-vue
的import及使用宣告1
2
3
4
5
6// import及使用
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
// 載入相關css
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css' - 安裝
jquery
及popper.js
因為我們專案使用bootstrap 4
版本,需要安裝jquery
及popper.js
1
2npm install jquery --save
npm install popper.js --save - 安裝
font-awesome
接著我們在1
npm install font-awesome
main.js
中載入相關css1
import 'font-awesome/css/font-awesome.css'
- 安裝我們的主角
axios
以上面所介紹的,我們在1
npm install axios
main.js
中加入defaults
設定值,先加入baseURL
吧1
2
3import axios from 'axios'
axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com'撰寫程式
這個範例會使用https://jsonplaceholder.typicode.com/posts做示範,先看一下回傳的object結構我們這篇的範例就示範印出1
2
3
4
5
6{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}title
及body
欄位。筆者就增加一點困難,我們就先列出title
欄位列表,然後點下title
後相對應的body
內容才會以collapse
效果彈出顯示,使用font-awesome
在顯示隱藏效果下,切換顯示 及 符號。body
欄位隱藏的狀態下會顯示 表示可以點開內容,若已顯示狀態下則切換顯示為 ,表示已打開內容。需求講完了,我們就來實際動手做吧。建立Component:AxiosDemo.vue
在Explorer
視窗中,直接在components上按右鍵加入AxiosDemo.vue
,我們先來宣告一下data部份,到時呼叫api後得到的response data使用這個data變數去接接下來我們就直接在1
2
3
4
5data() {
return {
postInfos: []
};
}created
事件中呼叫API,取得資料,因我們已經於main.js
中設置baseURL
,geturl只要設置相對路徑即可以上程式碼稍微要講解一下,我們先用1
2
3
4
5
6
7
8
9created: function() {
axios.get("/posts").then(response => {
let tempInfos = response.data;
tempInfos.forEach(item => {
item.show = false;
this.postInfos.push(item);
});
});
}tempInfos
接response data,之後再使用foreach
倒出資料時,順邊指定show
屬性,預設設為false
,其控制body
欄位資料顯示隱藏邏輯,設定好的資料push至我們的data變數postInfos
。
都設置完邏輯面的部份,我們來處理一下ui面吧,這裡會使用到bootstrap
中的card
結構,title
欄位資料放於card-header
中,body
資料放於card-body
中(預設隱藏)。
1 | <div class="card" |
上述程式碼使用到vue相關技巧如下
vue directive
有v-for
、v-show
- 事件監聽
v-on
如@click
javascript表達式
寫於@click
,將show改為目前show值相反值- 例:true改為false、false則反之。
- 一定要會的
Mustache語法
使用,將title
、body
欄位值印出
完整的AxiosDemo.vue
程式碼如下
1 | <template> |
設定Route
我們找到router\index.js
,擴充routes
陣列
1 | // 先import Component |
使用npm run dev
執行網站,效果如下
套用axios攔截器及loading效果
上面有介紹到interceptor攔截器
的功能,筆者就以上述範例繼續以擴充的方式完成
- 安裝loading效果實現套件
vue-blockui
1
npm install vue-blockui --save
- 接著在
main.js
中引入1
2
3
4// 將套件import進來
import BlockUI from 'vue-blockui'
// 套用於vue中
Vue.use(BlockUI) AxiosDemo.vue
頁面中加入vue-blockui
ui區塊1
2
3
4
5
6<!-- 使用data變數spinnerStatus來控制顯示與否 -->
<!-- 使用data變數msg來動態設定顯示字串 -->
<BlockUI :message="msg"
v-show="spinnerStatus">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
</BlockUI>- 上步驟宣告中有使用到
data
變數1
2
3
4
5
6
7data() {
return {
postInfos: [],
msg: "Loading...",
spinnerStatus: false
};
}, - 在
created
事件中加入相關程式碼1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25let $vue = this;
axios.interceptors.request.use(
function(config) {
$vue.spinnerStatus = true;
return config;
},
function(error) {
$vue.spinnerStatus = false;
return Promise.reject(error);
}
);
// 使用setTimeout是為了demo效果,不然資料撈太快,會沒看到loading效果
// 因此故意延遲3秒後才隱藏loading視窗
axios.interceptors.response.use(
function(response) {
setTimeout(function() {
$vue.spinnerStatus = false;
}, 3000);
return response;
},
function(error) {
$vue.spinnerStatus = false;
return Promise.reject(error);
}
); - 完整的程式碼(加入
axios.get
及axios.interceptors
)最終完成效果如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73<template>
<div id="axiosdemo">
<div class="card"
v-for="post in postInfos"
:key="post.id">
<div class="card-header"
@click="post.show = !post.show">
<i class="fa fa-plus-square-o"
v-show="!post.show"></i>
<i class="fa fa-minus-square-o"
v-show="post.show"></i> {{post.title}}
</div>
<div class="card-body"
v-show="post.show">
<p class="card-text">
{{post.body}}
</p>
</div>
</div>
<!-- blockui -->
<BlockUI :message="msg"
v-show="spinnerStatus">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
</BlockUI>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "AxiosDemo",
data() {
return {
postInfos: [],
msg: "Loading...",
spinnerStatus: false
};
},
created: function() {
let $vue = this;
axios.interceptors.request.use(
function(config) {
$vue.spinnerStatus = true;
return config;
},
function(error) {
$vue.spinnerStatus = false;
return Promise.reject(error);
}
);
// Add a response interceptor
axios.interceptors.response.use(
function(response) {
setTimeout(function() {
$vue.spinnerStatus = false;
}, 3000);
return response;
},
function(error) {
$vue.spinnerStatus = false;
return Promise.reject(error);
}
);
axios.get("/posts").then(response => {
let tempInfos = response.data;
tempInfos.forEach(item => {
item.show = false;
this.postInfos.push(item);
});
});
}
};
</script>
結論
我們建構應用程式最基本的功能就是CRUD,axios
套件是一定要投資的,筆者建議一定要花時間研究及練習,老話一句,一定要記得axios
提供哪些功能,這樣需要用到時,很快就能查出相對應的解法,介紹就到這邊,我們下篇再見。
範例檔案參考https://github.com/EugeneSu0515/VueDemoApp