这两天终于空下来了,打算优化下项目,发现在项目中,部分页面请求响应的很快,就会出现loading动画一闪而过的情况,用户体验很差。于是决定优化下loading动画。
直接去除loading动画肯定是不现实的,用户无法感知响应,这个阶段去改造成骨架屏也不合适,那么只能优化loading动画,让它显示的时间更长一些。
我们只要设置一个最小loading时间,当请求响应时间小于这个时间时,就等待剩余时间,这样就可以避免loading动画突然的闪烁。
示例代码
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
| async fetchData() { try { const minLoadingTime = 800; loading.value = true; const startTime = Date.now(); const response = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5'); const result = await response.json(); const elapsedTime = Date.now() - startTime; if (elapsedTime < minLoadingTime) { await new Promise(resolve => setTimeout(resolve, minLoadingTime - elapsedTime)); }
data.value = result; } catch (error) { console.error('请求失败:', error); alert('数据获取失败,请重试'); } finally { loading.value = false; } }
|
ok,这样的话,当请求低于800ms时,就会等待剩余时间,也就不会出现loading动画闪烁的情况了。
但是项目中有很多地方会去请求,我们不可能每个地方都加一遍,那么只能放在拦截器上统一处理了。
问题二来了,不是所有请求都需要loading动画的呀,这样的话我们就需要在拦截器上判断下。
首先抽象出loading的逻辑
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
| import { ref } from 'vue'
export function useRequest(minLoadingTime = 800) { const loading = ref(false)
const request = async (requestFn) => { try { loading.value = true const startTime = Date.now()
const result = await requestFn()
const elapsedTime = Date.now() - startTime if (elapsedTime < minLoadingTime) { await new Promise(resolve => setTimeout(resolve, minLoadingTime - elapsedTime)) }
return result } catch (error) { console.error('请求失败:', error) throw error } finally { loading.value = false } }
return { loading, request } }
|
接下来对拦截器进行改造
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
| useAxios.js import { ref } from 'vue' import axios from 'axios' import { useRequest } from './useRequest'
export function useAxios(config = {}) { const data = ref(null) const error = ref(null) const { withLoading = false, minLoadingTime = 800, ...axiosConfig } = config
const instance = axios.create(axiosConfig) const { loading, request: withMinLoading } = useRequest(minLoadingTime)
const execute = async (requestConfig) => { try { error.value = null if (withLoading) { const res = await withMinLoading(() => instance(requestConfig)) data.value = res.data return res } else { const res = await instance(requestConfig) data.value = res.data return res } } catch (err) { error.value = err throw err } }
return { data, error, loading, execute, } }
|
最后调用
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
| const { data:, loading, execute: fetchPosts, } = useAxios({ withLoading: true, minLoadingTime: 800, baseURL: 'https://jsonplaceholder.typicode.com' })
const { data, execute: fetchPostsNoLoading, } = useAxios({ baseURL: 'https://jsonplaceholder.typicode.com' })
const handleFetchWithLoading = () => { fetchPosts({ method: 'get', url: '/posts', params: { _limit: 5 } }) }
const handleFetchNoLoading = () => { fetchPostsNoLoading({ method: 'get', url: '/posts', params: { _limit: 5 } }) }
|
ok大功告成,这样就可以根据不同场景控制loading动画了。
我的微信公众号: 梨的前端小屋