前言
本文涉及到axios
,vuex
,vuex/modules
並且沒有覆蓋所有的專案情況,如果不符合你的技術棧,還請隨便看看。
如果不願意看作者扯淡,可以看github上的demo(typescript)。
另外,這個demo是使用了vue-cli@3.0
,ts
和class
寫的,如果不熟悉語法的,還請擔待。本文章的語法會依然使用js。
不建議在vue中使用ts,目前還沒有完全相容,元件中使用vuex的action也會丟失型別監測等等,感覺ts的語法相比eslint的檢測更適合團隊。
歡迎來我的Vue技術群交流:887516034
Axios
首先先封裝需要使用的請求api
//-- src/utils/api.js
import Axios from 'axios';
import qs from 'qs';
import store from '../store/' //-- src/store/index.js
import Vue from 'vue'
import router from '../router/'
import myCookie from './cookie'
//-- src/utils/cookie.js 這裡使用的是mdn網站的cookie封裝,附上鍊接
// https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework
//create方法會建立一個新的axios例項,並繼承axios幾乎所有屬性,配置和方法
//建議使用 create 方法封裝 api ,不對 axios 本身做特殊配置
const api = Axios.create({
//傳參是一個物件,配置包含baseUrl,timeout等等,既可以在這裡傳進去,也可以在例項化後設定配置
baseURL: process.env.NODE_ENV==="development"?'/api':'https://example.domain',
// 設定通用url,使用請求的方法時,就可以省略這個url
// 可以通過process.env.NODE_ENV判斷是否開發環境,來決定是否使用代理url
// 代理是用來解決跨域的。。
headers: {
//這個配置不用說了吧。預設攜帶請求頭,
//有的後臺更喜歡讓前端把session_id放在header裡傳送
},
transformRequest: [function (data, headers) {
// 此處是格式化發請求時,需要傳送的資料格式
// 某些後臺在處理資料時不識別預設的 payload
// 此處用第三方模組qs 轉換成 相容較好的 form-data(x-www-form-urlencoded)
return qs.stringify(data);
}],
timeout: 10000,//超時,超出這時間,就會Promise.reject(),單位ms
withCredentials: true,
// 允許瀏覽器端在發請求時,攜帶cookie一起傳送,
// 某些後臺語言會把session_id放在cookie裡返回給前端
// 如果這時不允許傳送cookie的話 那麼後臺會判斷是另一個瀏覽器在登入操作。
// 我都是在例項化後 配置這個屬性 因為我偶爾出現在這裡傳參配置會無效。
// 設定這個屬性為true後 ,後臺不可以把允許跨域設定為'*',必須指定ip或域名
proxy:{}//axios的代理我沒用過,不過看了下原始碼,也是開發環境才可以使用
});
//現在這裡再給例項化後的api 配置攔截 不是axios本身
//新增請求攔截器
api.interceptors.request.use(config => {
//在傳送請求之前做某事,比如說 設定loading動畫顯示
store.commit('loadingStart');
//此處我是把全域性loading動畫的控制放在vuex的,所以引入了store
return config
}, error => {
//請求錯誤時做些事
return Promise.reject(error)
});
//新增響應攔截器
api.interceptors.response.use(response => {
//對響應資料做些事,比如說把loading動畫關掉
store.commit('loadingOver');
return response.data
//此處我直接返回res.data,方不方便你們應該有點b數的
}, error => {
//請求錯誤時做些事
// error.response.status是後臺響應請求的狀態碼
// 可以根據自己專案的需求 執行操作
if (error.response.status===401){
//這裡引入vue是因為要使用掛載在vue原型上的element-ui的彈窗元件
// 因為這時掛載vue原型上的方法,這個import的vue並沒有例項化,無法省略prototype
Vue.prototype.$alert(error.response.data.msg,{
type:error.response.data.type,
title:'Message',
}).then(()=>{
myCookie.removeItem('user');
router.push({name:'SignIn'});//這裡就是引入router的目的
console.clear();
})
}
store.commit('loadingOver');//關閉動畫
return Promise.reject(error)
});
api.defaults.withCredentials = true;
// 允許傳送cookie,根據自己的專案需求是否需要開啟
// axios的更多配置可以看官方的文件 github的 readme.md
// https://github.com/axios/axios
export default api
複製程式碼
至此,一個簡單常用的api的配置部分封裝完成
這裡提一下proxy
的使用,好多人出過錯。
// https://github.com/chimurai/http-proxy-middleware
'/api':{
target:'http://example.domain',
changeOrigin: true, //是否需要虛擬站點,我也不懂啥意思。。好像寫不寫差不多
pathRewrite:{
//這個屬性,是看後臺介面的請求url中是否有你配置的這個api
//如果有的話你就不用寫這個屬性,
//如果沒有,你就需要寫
'^api':'',//把你本地請求的url中的api欄位去掉
}
}
//以上的配置效果是
//-- /api/xxx --->>> http://example.domain/xxx
// 如果不寫pathRewrite
//-- /api/xxx --->>> http://example.domain/api/xxx
複製程式碼
當專案中需要多個url時,再建一個檔案,再create一個例項就可以,使用哪個就引入哪個,分開維護,很方便。
Service
這裡我們封裝完api的url和請求配置部分,下面就要封裝具體的請求。這裡我定義為services
//-- src/services/user.js 這裡可以把請求整理成模組,如果請求介面較多,後期維護方便
import api from '../utils/api'
// 引數是es6的解構,小白自己去看 阮老師 的 es6
// USER_REGISTER宣告為一個方法
export const USER_REGISTER = ({user,password,email,phone,code}) => {
return api.post('/register',{//此處 post '/register' ===>> baseURL+'/register'
user,password,email,phone,code
// es6 物件的鍵值對字元相同時的寫法
})
};//註冊介面
export const USER_LOGIN = ({user,password}) => {
return api.post('/signIn',{user,password});
};//登入介面
// 我這裡匯出的是多個方法名的集合,是一個物件,
// 可以通過 import { USER_LOGIN,USER_REGISTER } from '...' 使用
// 這裡就舉例 2個 不詳細寫了
複製程式碼
這裡提一下,很多小夥伴對axios的使用文件不熟悉,在get和post時,經常出現2個方法的混餚,傳參出錯,建議對不熟悉語法的,不要使用‘省略式’的寫法,下面可以看一下詳細寫法,可以減少出錯率。(其實就是官方文件的。)
axios({
url:'...',
method:'...',
headers:{},
params:{},//這個是get攜帶請求引數用的,拼接在url的,直接寫在url上也可以,
data:{},// 這個是post put patch請求傳送的資料
})
複製程式碼
Vuex
現在我們已經封裝完成完整的api了,如果覺得沒必要使用vuex,可以直接引入services
的user.js
直接使用了。
import { USER_LOGIN } from '@/services/user'
USER_LOGIN({user,password}).then().catch()
複製程式碼
為什麼要用加入vuex,vuex的action
是用來處理非同步操作的,同時vuex的state
是整個專案元件之間資料流動的重要環節,多數資料會在元件之間通用,將api請求放在action
中可以更合理的讀寫state
,不多說,上程式碼。
個人習慣,一用vuex就喜歡直接使用模組(namespaced),這裡推薦vuex多使用模組,在團隊開發中提供很大的便利,右轉vuex官網。
//-- src/store/modules/user/action.js
import { USER_INFO } from '@/services/user'
export default {
async getInfo({ commit }){
try{ //請求成功
const data = await USER_INFO();
commit('setUserInfo',data);
//模組的action中使用commit,不需要使用namespace字首
return data
// async函式的返回值,預設會以promise.resolve(data)的形式
}catch(e){
//請求失敗或者程式碼塊出錯
return e
}
}
}
//合理使用 async/await 可以讓邏輯程式碼更清晰
複製程式碼
//--- src/store/modules/user/commit.js
export default {
setUserInfo(state,data){
state.info = data
}
}
複製程式碼
<!-- 此處假設已經呼叫getInfo請求 -->
<template>
<div>
<p>{{info.name}}</p>
<p>{{info.age}}</p>
<img :src="info.photo" />
</div>
</template>
<script>
import { mapState } from 'vuex'
export default{
//...
computed:{
//需要使用模組中資料時,第一個引數為模組名
...mapState('user',{
info:'info'
})
}
}
</script>
複製程式碼
tips:懂得分享才能走的更遠。
歡迎來我的Vue技術群交流:887516034
如果覺得對你有用,就打賞一下吧。