在前端工程中,常常會透過 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 提昇使用者的使用體驗,可以之後列成優化項目。