vue对ajax进行封装从而全局简单调用

vue对ajax进行封装从而全局简单调用
具体操作具体更改,这里的apiMap是默认自动更新的接口文档,可以自己删掉进行更改
全局挂载

import Vue from 'vue'
import apiMap from './apis.js'
let loadingNum = 0
let loadingTimeout
let loading
let loadingTimes = 0
Vue.prototype.http = async function ({cmd, type, input, success, error, complete, ...arg}) {
  let self = this
  if (!apiMap[cmd]) {
    throw new Error('找不到 api:' + cmd + ', 请确认')
  }
  let isAjaxComplete = false
  addLoading()
  let http = await ajax()
  let result = responseHandler(http)
  reduceLoading()
  return result
  async function ajax () {
    let _http
    await new Promise(resolve => {
      const http = new XMLHttpRequest()
      http.onreadystatechange = function () {
        if (http.readyState === 4) {
          _http = http
          isAjaxComplete = true
          resolve()
        }
      }
      let url = window.config.host + apiMap[cmd].uri + '?src=H5'
      if (!input) {
        input = {}
      }
      input = JSON.parse(JSON.stringify(input))
      if (apiMap[cmd].type === 'GET') {
        var getParam = '&'
        Object.keys(input).forEach(function (key) {
          var item = input[key]
          if (key === 'pIdx') {
            item = item - 1
          }
          if (typeof item === 'object') {
            if (item instanceof Array) {
              // 数组进行逗号组合为字符串
              if (item.length > 0) {
                item = item.join(',');
                getParam += key + '=' + item + '&'
              }
            } else {
              item = encodeURIComponent(item)
              getParam += key + '=' + JSON.stringify(item) + '&'
            }
          } else if (item || item === 0) {
            item = encodeURIComponent(item)
            getParam += key + '=' + item + '&'
          }
        })
        if(!getParam.includes('mchId')){
          getParam += 'mchId=' + window.localStorage.mchId + '&'
        }
        if (getParam === '&') {
          getParam = ''
        }

        url += getParam.replace(/&$/, '')
      } else if (apiMap[cmd].type !== 'DELETE') {
        removeEmpty(input)
      }
      http.open(apiMap[cmd].type || 'POST', url.replace(/\{.+\}/, arg.id), true)
      http.setRequestHeader('sessionId', window.localStorage.sessionId)
      http.setRequestHeader('Content-type', 'application/json')
      http.send(JSON.stringify(input))
    })
    return _http
  }
  function responseHandler (http) {
    if (!http.responseText) {
      return {code: 'failed', msg: '请求无响应'}
    }
    let res = JSON.parse(http.responseText)
    if (http.status === 200) {
      if (res.code === 401) {
        // window.location.href = window.location.href.split('/#/')[0] + '/login.html'
        // uni.postMessage({
        //   data: {
        //     type:'navigateToMiniProgram',
        //   },
        //   success(){
        //     // uni.navigateBack()
        Vue.prototype.$toast.fail('当前登录已过期,请重新登录')
        setTimeout(() => {
          uni.navigateTo({url:'/pages/login/index'})
        }, 1000);
        //   }
        // });
        return
      } else if (res.code !== 200 && (!success || !success.toString().includes('$message'))) {
        // 如果状态码不是 200,并且 success 函数里没有提示相关的错误信息,那么这里提示一下 TODO 会不会有不需要提示的情况 ?
        // Vue.prototype.$message.error(res.msg)
        Vue.prototype.$toast.fail(res.msg)
      }
      if (res.msg === 'OK') {
        res.msg = '操作成功'
      }
      success && success.call(self, res)
    } else {
      error && error.call(self, res)
    }
    complete && complete.call(self, res)
    return res
  }
  
  function addLoading () {
    loadingNum++
    if (loadingTimeout) return
    loadingTimeout = setTimeout(() => {
      // loading了 n 次了, 友情提示一下
      // 第一次 loading 2次, 提示一下
      // 之后每 loading 5次, 提示一下
      if (!isAjaxComplete) {
        loadingTimes++
        let target = document.getElementById("loading-overlay")
        if (target) {
          target.style.display = 'flex'
          loading = target
        }
        if (loadingTimes === 2) {
          // Vue.prototype.$message.warning('您的网络比较差, 操作响应时间会比较长, 请耐心等候')
          loadingTimes = -3
        }
      }
    }, 1000)
  }
}
function reduceLoading () {
  loadingNum--
  if (loadingNum <= 0) {
    clearTimeout(loadingTimeout)
    loadingTimeout = loadingNum = 0
    if (loading) {
      console.log("关闭loading")
      document.getElementById("loading-overlay").style.display = 'none'
      loading = null
    }
  }
}

// 过滤空字符串为 undefined
function removeEmpty (obj) {
  if (obj instanceof Array) {
    obj.forEach(removeEmpty)
  } else {
    Object.keys(obj).forEach(key => {
      if (obj[key] === '') {
        obj[key] = undefined
      }
    })
  }
}

实际用法:

getData(){
      this.http({
      cmd: 'GETIdxReportStats',
      input: {enable:'off'},
      id: '123',
      success (res) {
        console.log(res)
      }
    });
}

在这里插入图片描述

### 封装 AJAX 请求于 Vue 3 在现代前端开发环境中,Vue 3 推荐使用 Axios 进行 HTTP 请求处理[^2]。通过创建一个专门用于发送请求的服务文件,可以使项目结构更加清晰,并简化组件内的调用逻辑。 #### 创建服务模块 `apiService.js` 为了提高可维护性和复用率,建议新建一个名为`apiService.js`的文件来集中管理所有的 API 调用: ```javascript import axios from 'axios'; // 设置默认配置项 const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // 应用的基础 URL 地址 timeout: 5000 // 请求超时时间 (毫秒) }); // 添加请求拦截器 service.interceptors.request.use( config => { // 在发送请求之前做些什么 return config; }, error => { // 对请求错误做些什么 return Promise.reject(error); } ); // 添加响应拦截器 service.interceptors.response.use( response => { // 对响应数据做点什么 return response.data; // 返回的数据通常是response中的data部分 }, error => { // 对响应错误做点什么 return Promise.reject(error); } ) export default service; ``` 此段代码定义了一个全局可用的 Axios 实例并设置了基本参数以及请求/响应拦截器以便统一处理跨域凭证、加载状态显示等问题[^1]。 #### 使用自定义 Hook 处理取消重复请求 考虑到用户体验优化的需求,在某些场景下可能需要支持取消正在进行中的请求以防止不必要的资源浪费。为此可以在组合式API(composition api)内利用钩子函数(hook)配合AbortController实现这一功能[^4]: ```javascript import { ref } from "vue"; import service from './apiService'; function useAxiosWithCancel(url){ let cancelSource = null; function fetchData(){ if(cancelSource !== null){ cancelSource.cancel('Operation canceled due to new request.'); } const CancelToken = axios.CancelToken; cancelSource = CancelToken.source(); return service.get(url,{ cancelToken:cancelSource.token, }).then(response=>{ console.log(`Success:${JSON.stringify(response,null,' ')}`); return response; }).catch(thrown=>{ if(axios.isCancel(thrown)){ console.log('Request canceled',thrown.message); }else{ throw thrown; } }); } return {fetchData}; } export default useAxiosWithCancel; ``` 上述实现了当发起新的相同路径下的GET请求时会自动终止前一次未完成的操作;同时提供了友好的日志输出帮助开发者调试问题所在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_小郑有点困了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值