vue:项目防抖axios防止重复提交封装+自带loading锁按钮

1,528 阅读2分钟

项目防抖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