Axios封装
一、全局loading效果通常在vue项目中使用最多的第三方请求库就是axios了,以此来实现与后台的数据交互。而在我们请求后台数据的时候,响应时间是不确定的,用户可能不知道我点了按钮之后它“怎么”了?所以我们通常需要一个loading效果,来告诉用户:我点了按钮之后又反应了,它让我等一会儿。但如果我们在每次请求的时候都去手动加一个loading效果,这无疑是很麻烦的,包括后期的维护成本也是很高的
·
一、全局loading效果
通常在vue项目中使用最多的第三方请求库就是axios了,以此来实现与后台的数据交互。而在我们请求后台数据的时候,响应时间是不确定的,用户可能不知道我点了按钮之后它“怎么”了?所以我们通常需要一个loading效果,来告诉用户:我点了按钮之后又反应了,它让我等一会儿。
但如果我们在每次请求的时候都去手动加一个loading效果,这无疑是很麻烦的,包括后期的维护成本也是很高的,而且当有多次请求同时触发时,相应的会多次触发loading。
因此我们需要对loading进行统一封装管理。
1、对axios库进行二次封装
需求分析:
- 当发送请求时触发loading效果,在请求结束后移除loading
- 当存在多个请求时需要确保只有一个loading,不能出现多个
- 当一次请求完成后,立即发起了另外一个请求,此时会出现loading闪烁的情况,需要进行防抖处理
- 所有请求的loading效果需要可配置,默认每个请求都有loading效果,可配置请求无loading
- 默认所有loading的效果是body覆盖于之上的,可配置覆盖指定元素之上
说明:
- 主库:axios
- loading效果实现:ElementUI的loading组件
- 错误消息提示:ElementUI的Message组件
- 防抖:lodash的debounce防抖
- showLoading:设置是否显示loading
- loadingTarget:设置loading效果覆盖的元素
代码实现:
import axios from 'axios'
import { Message, Loading } from 'element-ui'
import _lodash from 'lodash'
import { baseURL } from '../common/env.js'
// loading对象
let loading
// 当前正在请求的数量
let underwayRequestCount = 0
// 显示loading
const showLoading = target => {
// 后面这个判断很重要,因为关闭时加了抖动,此时loading对象可能还存在,
// 但underwayRequestCount已经变成0.避免这种情况下会重新创建个loading
if (underwayRequestCount === 0 && !loading) {
loading = Loading.service({
lock: true,
text: 'Loading...',
background: 'rgba(255, 255, 255, 0.5)',
target: target || 'body'
})
}
underwayRequestCount++
}
// 隐藏loading
const hideLoading = () => {
underwayRequestCount--
underwayRequestCount = Math.max(underwayRequestCount, 0) // 做个保护
if (underwayRequestCount === 0) {
// 关闭loading
toHideLoading()
}
}
// 防抖:将 300ms 间隔内的关闭 loading 合并为一次。防止连续请求时, loading闪烁的问题。
let toHideLoading = _lodash.debounce(() => {
loading.close()
loading = null
}, 300)
// 请求成功
const requestSuccess = config => {
console.log(config)
// 判断当前请求是否设置了不显示Loading
if (config.headers.showLoading !== false) {
showLoading(config.headers.loadingTarget)
}
// 获取token,在请求中添加 token
let token = ''
if (sessionStorage.getItem('wti-manager-token')) {
token = sessionStorage.getItem('wti-manager-token')
token = token ? '' + token : ''
}
config.headers.Authorization = token
return config
}
// 请求失败
const requestFault = err => {
// 判断当前请求是否设置了不显示Loading(不显示自然无需隐藏)
if (err.config.headers.showLoading !== false) {
hideLoading()
}
Message.error('请求超时!')
return Promise.resolve(err)
}
// 响应成功
const responseSuccess = response => {
// 判断当前请求是否设置了不显示Loading(不显示自然无需隐藏)
if (response.config.headers.showLoading !== false) {
hideLoading()
}
// 如果用户登录过期了
if (response.data.code === 401) {
Message({
message: '登陆认证已过期,请重新登陆!',
type: 'warning'
})
// 如果不是请求成功
} else if (response.data.code !== 200 && response.data.code !== 201) {
Message({
message: response.data.msg,
type: 'warning'
})
}
return response.data
}
// 响应失败
const responseFault = error => {
// 判断当前请求是否设置了不显示Loading(不显示自然无需隐藏)
if (error.config.headers.showLoading !== false) {
hideLoading()
}
// 对错误数据进行处理
if (error.response && error.response.data && error.response.data.message) {
let jsonObj = JSON.parse(error.response.data.message)
Message.error(jsonObj.message)
} else {
Message.error(error.message)
}
return Promise.reject(error)
}
// 设置axios的默认项
axios.defaults.baseURL = baseURL
axios.defaults.timeout = 40000
axios.interceptors.request.use(requestSuccess, requestFault)
axios.interceptors.response.use(responseSuccess, responseFault)
// 生成 axios 对象
const generateAxios = config => {
const newAxios = axios.create(config)
newAxios.interceptors.request.use(requestSuccess, requestFault)
newAxios.interceptors.response.use(responseSuccess, responseFault)
return newAxios
}
const post = (url, data, headers) => {
return axios({
method: 'post',
url,
headers,
data
})
}
const get = (url, params, headers) => {
return axios({
method: 'post',
url,
headers,
params
})
}
export {
generateAxios,
post,
get
}
2、使用
默认全屏loading
// passwordLogin:封装过的方法
/*
passwordLogin (payload, headers) {
return post('/wkbbackend/login/password', payload, headers)
}
*/
// 普通请求
this.$http.passwordLogin(data).then(res => {
if (res.code === 200) {
const Authorization = res.data.login.Authorization
sessionStorage.setItem('wti-manager-token', Authorization)
this.$message.success('登录成功')
} else {
this.$message.error('登录失败')
}
})
不需要显示loading
// 设置不显示loading
this.$http.passwordLogin(data, {showLoading: false}).then(res => {
if (res.code === 200) {
const Authorization = res.data.login.Authorization
sessionStorage.setItem('wti-manager-token', Authorization)
this.$message.success('登录成功')
} else {
this.$message.error('登录失败')
}
})
loading指定显示在某个dom元素上
// 设置loading显示的dom
this.$http.passwordLogin(data, {loadingTarget: '#loading-box'}).then(res => {
if (res.code === 200) {
const Authorization = res.data.login.Authorization
sessionStorage.setItem('wti-manager-token', Authorization)
this.$message.success('登录成功')
} else {
this.$message.error('登录失败')
}
})
更多推荐
已为社区贡献13条内容
所有评论(0)