项目防抖axios防止重复提交封装+自带loading锁按钮
在项目中,表单提交或者许多接口高频点击等,我们需要岁项目的请求进行一些优化。项目使用ele + axios。
一、loading锁按钮组件
提交表单时,点击立即按钮loading,等待接口返回或异步操作介绍后进行解锁,取消loading。
1.loading组件
自定义个一公共组件,方便多处使用
<template>
<div @click="handleClick">
// 使用v-bind="$attrs"兼容`ele`的原始参数
<el-button
v-bind="$attrs"
:loading="loadVisible"
>
<slot />
</el-button>
</div>
</template>
<script>
export default {
//兼容回调函数所需要的`参数`
props:['params'],
data(){
return{
loadVisible:false
}
},
methods:{
handleClick(){
this.loadVisible = true
//将关闭的操作作为回调传回
let closeLoading =()=>{
this.loadVisible = false
}
this.$emit('afterClick',this.params?this.params:closeLoading ,closeLoading)
}
}
}
</script>
2.使用组件
按照 vue 的两种方法皆可引入
<template>
<load-btn type="primary" size="mini" @afterClick="handleTextLoadingBtn" :params="
{messege:'hello'}">测试</load-btn>
</template>
<script>
export defalut {
methods:{
handleTextLoadingBtn({ message },done){
console.log(message)
//模拟接口返回
setTimeOut(() => {
done()
},5000)
}
}
}
</script>
二、axios防止重复提交
按照事件队列的设计,我们维护一个数组,将需要进行防抖的接口存入数组中,返回之后进行移除,在axios请求是进行拦截,如果该请求上一次重新还未返回,则取消本次请求。
import { serialize } from '@/util/util'
import NProgress from 'nprogress' // progress bar
import router from '@/router/router'
import { Message } from 'element-ui'
import 'nprogress/nprogress.css'
import qs from 'qs'
import store from '@/store' // progress bar style
import axios from 'axios'
/// 声明一个数组
let pending = []
const CancelToken = axios.CancelToken
//取消请求的方法
const removePending = (config) => {
for (const p in pending) {
// 当前请求在数组中存在时执行函数体
if (pending[p].u === config.url + '&' + config.method) {
pending[p].f() // 执行取消操作
pending.splice(p, 1) // 把这条记录从数组中移除
}
}
}
//移除请求,维护pending数组
const removePendingArray = c => {
pending.splice(pending.indexOf(c), 1)
}
//基本路径
axios.defaults.baseURL = '/'
//请求超时
axios.defaults.timeout = '5000'
axios.defaults.validateStatus = function (status) {
return status >= 200 && status <= 500 // 默认的
}
// 跨域请求,允许保存cookie
axios.defaults.withCredentials = true
// NProgress Configuration
NProgress.configure({
showSpinner: false
})
// HTTPrequest拦截
axios.interceptors.request.use(config => {
NProgress.start() // start progress bar
const TENANT_ID = getStore({ name: 'tenantId' })
const isToken = (config.headers || {}).isToken === false
const token = store.getters.access_token
config.headers['version'] = '3.1'// token
config.headers['APP-ID'] = store.getters.currentApp || ""
if (token && !isToken) {
config.headers['Authorization'] = 'Bearer ' + token// token
}
if (TENANT_ID) {
config.headers['TENANT-ID'] = TENANT_ID // 租户ID
}
// headers中配置serialize为true开启序列化
if (config.method === 'post' && config.headers.serialize) {
config.data = serialize(config.data)
delete config.data.serialize
}
if (config.method === 'get') {
config.paramsSerializer = function (params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
}
let preventRepeat = config.preventRepeat || false
if (preventRepeat) {
removePending(config); //防止多次触发请求
config.cancelToken = new CancelToken((c) => {
pending.push(
{
u: config.url + '&' + config.method,
f: c
}
)
})
}
return config
}, error => {
return Promise.reject(error)
})
// HTTPresponse拦截
axios.interceptors.response.use(res => {
NProgress.done()
const status = Number(res.status) || 200
const message = res.data.msg || "未知错误"
if (status === 401) {
Message({
message: message,
type: 'error'
})
store.dispatch('FedLogOut').then(() => {
router.push({ path: '/login' })
})
return
}
if (status !== 200 || res.data.code == 500 || res.data.code == 1) {
Message({
message: res.data.msg?res.data.msg:"未知错误",
type: 'error'
})
console.error("接口发生请求失败,服务器发生错误")
return Promise.reject(new Error(message))
}
removePendingArray(res.config)
return res
}, error => {
NProgress.done()
return Promise.reject(new Error(error))
})
export default axios