之前寫了 axios 的基本用法與搭配 axios create() 的使用方法,之前有看過前輩把 loading 寫在 interceptors 攔截器中,在 .interceptors.request.use()中用 Jquery() 控制 CSS 打開 loading 效果,.interceptors.response.use() 中關掉 loading 效果。在這裡我想利用 pinia 共用 loading 的狀態,利用 .interceptors.request.use() 與 .interceptors.response.use(),開關 vue-loading-overlay 的效果。
先看這兩篇:
也要稍微了解一下 pinia 的用法。
安裝 pinia
npm install pinia
安裝 axios
npm install axios
安裝 vue-loading-overlay
npm install vue-loading-overlay@^6.0
檔案結構

resource/index.js 是有關 axios create() 跟 interceptors 相關設定。
stores/user.js 是有關 pinia 共用 loading 控制變數的設定。
store/user.js 設定
isLoading 是一個布林值,初始值為 false,用來控制 loading 元件的開關,放在pinia stores中,要傳到 resource/index.js 及有用到 loading 元件的 vue 檔中共用。
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => {
return { isLoading: false };
},
// 也可以这样定义
// state: () => ({ isLoading :false })
});
resource/index.js 設定
在resource/index.js 中引入 axios 與 stores 的 user.js 。
import axios from 'axios';
import { useUserStore } from '@/stores/user.js';
設定 axios.create
export const randomUser = axios.create();
randomUser.defaults.baseURL = '<https://randomuser.me/>';
.interceptors.request.use 設定
要把控制 loading 的共享變數放入,這樣就可以在打 API 的 request 與收到 response 時跑 loading 效果:
const userStore = useUserStore();
userStore.isLoading = true;
注意:const userStore = useUserStore(); 如果放在 randomUser.interceptors.request.use() 的外面會報錯。
完整的 resource/index.js
import axios from 'axios';
import { useUserStore } from '@/stores/user.js';
// const userStore = useUserStore() 放在外面這裡 會報錯!!!
// const userStore = useUserStore()
export const randomUser = axios.create();
randomUser.defaults.baseURL = '<https://randomuser.me/>';
randomUser.interceptors.request.use(
(config) => {
const userStore = useUserStore();
// 打開 loading
userStore.isLoading = true;
console.log('useUserStore', userStore.isLoading);
return config;
},
(error) => {
const userStore = useUserStore();
// 關掉 loading
useUserStore.isLoading = false;
return Promise.reject(error);
}
);
randomUser.interceptors.response.use(
(response) => {
const userStore = useUserStore();
// 關掉 loading
userStore.isLoading = false;
return response;
},
function (error) {
const userStore = useUserStore();
// 關掉 loading
userStore.isLoading = false;
return Promise.reject(error);
}
);
在 vue 檔中設定
引入 store 的變數
// 引入 store
import { useUserStore } from '@/stores/user.js';
// store
const userStore = useUserStore();
引入 loading 元件
import Loading from 'vue-loading-overlay';
在 <template> 中放入 loading 元件(在這裡以元件方式來做,而非 plugin 方式)。其中 color 與 is-full-page 要綁定到 color 跟 fullPage 這兩個 ref 變數。
v-model:active=”userStore.isLoading” 則是綁定到 store 的 isLoading 變數,控制 loading效果的開關。
<template>
<header>
<loading
v-model:active="userStore.isLoading"
:can-cancel="true"
:color="color"
:is-full-page="fullPage"
/>
<div class="wrapper">Loading 效果</div>
</header>
</template>
設定完以上,可以發現 randomUser.get(‘api/’) 時,在 request 與 response 之間會有 loading 動畫效果。
<script setup>
import { ref } from 'vue';
// 引入 axios 攔截器
import { randomUser } from '@/resource/index.js';
// 引入 store
import { useUserStore } from '@/stores/user.js';
// 引入 vue-loading-overlay
import Loading from 'vue-loading-overlay';
// store
const userStore = useUserStore();
// vue-loading-overlay 設定
const color = ref('#ff0000');
const fullPage = ref(true);
randomUser.get('api/').then((res) => {
console.log('res', res);
});
</script>
<template>
<header>
<loading
v-model:active="userStore.isLoading"
:can-cancel="true"
:color="color"
:is-full-page="fullPage"
/>
<div class="wrapper">Loading 效果</div>
</header>
</template>
如果打 API 時如果要帶 tokent 也可以放在 .interceptors.request.use 中,就不用每次打 API 都要寫一遍,這也是實戰時常用的技巧。
randomUser.interceptors.request.use(request => {
request.headers.common.Authorization = `Bearer ${localStorage.getItem('token')}`
return request
})
