
在前端工程中,常常會透過 ajax 向後端做非同步資料交換,但api 可能會因各種因素延遲回應,為提昇更好的使用者體驗,通常都會做一個過場的動畫,讓使用者得知正在加載資料。
而大多數套件設計的相當簡易,背後可能只是一個 boolean 值,在多個併發的非同步的ajax request ,只要有任一個 request,提前回來就被關掉 loading 的過場動畫。
在 vuex 中 做個計數器功能, ajax 發出 request 時,就呼叫 store 中的increment方法,讓count 就加1,完成或失敗則 count 減1,並提供 isLoading 的 getter 給畫面判斷, 透過封裝 axios 來由外部傳入參數決定需不需要 show loading 轉場動畫。
import { generatorUUID } from '@/utils'
var _ = require('lodash')
const state = {
count: []
}
// getters
const getters = {
isLoading: (state) => {
return state.count.length > 0
},
removeByItems: (state) => {
return state.count.filter(x => x.isRemoveByRequestId === true)
}
}
// mutations
const mutations = {
increment(state, requestId) {
const isRemoveByRequestId = requestId !== '' && requestId !== undefined
requestId = requestId || generatorUUID()
var newLoading = { requestId: requestId, isRemoveByRequestId: isRemoveByRequestId }
state.count.push(newLoading)
},
decrement(state, requestId) {
if (requestId) {
var index = state.count.findIndex(item => item.requestId === requestId)
state.cart.splice(index, 1)
} else {
const newCount = _.cloneDeep(state.count).filter(x => x.isRemoveByRequestId === false)
if (newCount.length > 0) {
newCount.shift()
state.count = newCount
}
}
}
}
// actions
const actions = {
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
function apiAxios(method, url, params, hideLoading, requestId) {
// 顯示loading
const appParams = {}
params = { ...appParams, ...params }
const httpDefault = {
method: method,
baseURL: baseURL,
url: url,
hideLoading: hideLoading,
requestId: requestId,
// `params` 是即將與請求一起發送的 URL 參數
// `data` 是作為請求主體被發送的數據
params: method === 'GET' || method === 'DELETE' ? params : null,
data: method === 'POST' || method === 'PUT' ? params : null,
timeout: 100000
}
if (httpDefault['hideLoading'] === false) {
store.commit('loading/increment', httpDefault['requestId'])
}
return new Promise((resolve, reject) => {
axios(httpDefault)
.then((res) => {
if (httpDefault['hideLoading'] === false) {
store.commit('loading/decrement', requestId)
}
resolve(successState(res))
})
.catch((response) => {
if (httpDefault['hideLoading'] === false) {
store.commit('loading/decrement', requestId)
}
errorState(response)
})
})
}
Vue.prototype.$getAxios(${process.env.VUE_APP_BASE_API}/api/v1/home/query, null, true)
現今越來越多網站 採用 Skeleton 提昇使用者的使用體驗,可以之後列成優化項目。