如何在 Axios 中去控制 Loading?大有学问!
目录
前言
按钮loading
局部loading
全局loading
前言
loading 的展示和取消可以说是每个前端对接口的时候都要关心的一个问题。这篇文章将要帮你解决的就是如何结合axios更加简洁的处理loading展示与取消的逻辑。
首先在我们平时处理业务的时候loading一般分为三种:按钮loading,局部loading,还有全局loading。
按钮loading
其实想写这篇博客的诱因也是因为这个按钮 loading ,在大多数时候我们写按钮 loading 业务的时候是这样写的。
const loading = ref(false)
try {loading.value = trueconst data = await axios.post(`/api/data`)
}
finally {loading.value = false
}
或者这样的写的
const loading = ref(false)
loading.value = true
axios.post(`/api/data`).then(data => {//do something}).finally(() => {loading.value = false})
可以看到 我们总要处理loading的开始与结束状态。而且好多接口都要这么写。这样太繁琐了,那我们可不可以这样呢?
const loading = ref(false)
const data = await axios.post(`/api/data`,{loading:loading})
把loading的状态给axios统一处理。这样代码是不是就简洁多了呢?处理方式也很简单。
// 请求拦截器
axios.interceptors.request.use(config = >{if (config.loading) {config.loading.value = true}
})
// 响应拦截器
axios.interceptors.response.use(response => {if (response.config.loading) {res.config.loading.value = false}},error => {if (error.config.loading) {config.loading.value = false}}
)
我们只需要在axios的拦截器中改变loading的值就可以,注意一定要传入一个ref类的值。这种写法也仅适用于vue3。vue2是不行的。
在vue2里面我们可能会想到这样写。
<template><a-button loading="loading.value">保存</a-button>
</template><script>export default {data () {return {loading: { value: false },}},mounted () {const data = await axios.post(`/api/data`,{loading:this.loading})},}
</script>
//拦截器和vue3写法一样
但是很遗憾这样是无法生效的。原因如下
//接口调用
axios.post(接口地址,配置项)
//拦截器
axios.interceptors.request.use(配置项 => {})
在axios中我们接口调用传入的配置项 和 拦截器返回的配置项 并不是同一个内存地址。axios做了深拷贝处理。所以传入的loading对象和返回的loading对象并不是同一个对象。所以我们在拦截器中修改是完全没有用的。
可是vue3为什么可以呢?因为 ref 返回的对象是 RefImpl 类的实例,并不是一个普通的对象,axios在做深拷贝的时候没有处理这种实例对象。所以我们就可以从这里出发来改造一下我们的axios写法。代码如下:
axios代码:
const _axios = axios.create({method: `post`,baseURL: process.env.VUE_APP_BASE_URL,
})
//注意:拦截器中比vue3多了个loading!!!
// 请求拦截器
_axios.interceptors.request.use(config = >{if (config.loading) {config.loading.loading.value = true}
})
// 响应拦截器
_axios.interceptors.response.use(response => {if (response.config.loading) {res.config.loading.loading.value = false}},error => {if (error.config.loading) {config.loading.loading.value = false}}
)export const post = (url, params, config) => { if (config?.loading) {class Loading {loading = config.loading}config.loading = new Loading()}return _axios.post(url, params, config)
}
使用方式:
<template><a-button loading="loading.value">保存</a-button>
</template><script>import { post } from '@api/axios'export default {data () {return {//这里的loading可以取任意名字。但是里面必须有valueloading: { value: false },}},mounted () {const data = await post(`/api/data`,{loading:this.loading})},}
</script>
可以看到实现的原理也很简单。我们在axios里面把出传入的config中的loading对象也变成一个实例对象就好了。在实例对象中记录我们传入的对象,也是以为这里我们会比vue3的写法多一个loading,从而实现响应式。
局部loading
局部loading的添加有两种方式:
-
·使用自定义指令 传入true和false 。这样的缺陷是不够灵活,组件内的元素就很难局部添加了,只能全组件添加。值得一提的是,改变true和false的逻辑就可以用我们上述的按钮loading方法。具体的实现方式这里就不再讲述了,如果需要的话可以评论区留言。
-
·在axios中封装。每次调用接口的时候传入需要添加loading的dom。接口调用完毕删除dom。实现方法如下。
这里是vue3 + antdV3 技术栈的一个封装。这里用hooks把设置删除loading的逻辑给拆了出去。
axios代码:
const _axios = axios.create({method: `post`,baseURL: import.meta.env.VITE_BASE_URL,
})const { setLoading, deleteLoading } = useAxiosConfig()
// 请求拦截器
_axios.interceptors.request.use(config = >{setLoading(config)
})
// 响应拦截器
_axios.interceptors.response.use(response => {deleteLoading(res.config)},error => {deleteLoading(res.config)}
)export const post = (url, params, config) => { return _axios.post(url, params, config)
}
hooks代码
import { createApp } from 'vue'
import QSpin from '@/components/qSpin/QSpin.vue'
import type { RequestConfig, AxiosError } from '@/types/services/http'
export default function () {/** 使用WeakMap类型的数据 键名所指向的对象可以被垃圾回收 避免dom对象的键名内存泄漏 */const loadingDom = new WeakMap()/*** 添加局部loading* @param config*/const setLoading = (config: RequestConfig) => {const loadingTarget = config.domif (loadingTarget === undefined) returnconst loadingDomInfo = loadingDom.get(loadingTarget)if (loadingDomInfo) {loadingDomInfo.count++} else {const appExample = createApp(QSpin)const loadingExample = appExample.mount(document.createElement(`div`)) as InstanceType<typeof QSpin>loadingTarget.appendChild(loadingExample.$el)loadingExample.show(loadingTarget)loadingDom.set(loadingTarget, {count: 1, //记录当前dom的loading次数appExample,})}}/*** 删除局部loading* @param config*/const deleteLoading = (config: RequestConfig) => {const loadingTarget = config.domif (loadingTarget === undefined) returnconst loadingDomInfo = loadingDom.get(loadingTarget)if (loadingDomInfo) {if (--loadingDomInfo.count === 0) {loadingDom.delete(loadingTarget)loadingDomInfo.appExample.unmount()}}}return { setLoading, deleteLoading }
}
基础逻辑,很简单。只需要接口请求的时候的添加loading ,接口响应完成的时候删除loading。但是随之而来的就有一个问题,如果多个接口同时请求 或者 一个接口频繁请求需要覆盖的都是同一个dom,这样我们添加的loading就会有很多个相同的,相互覆盖。因此上述代码定义了一个loadingDom 记录当前正在loading的dom有哪些,如果有一样的进来的 就把count加一 ,结束后就把count减一。如果count为零则删除loading。
使用实例代码:
<template><div><div ref="head_dom">我是头部数据</div><a-card ref="card_dom">我是卡片内容</a-card></div>
</template><script setup lang="ts">import { post } from '@api/axios'import { ref, onMounted } from 'vue'const head_dom = ref()const card_dom = ref()//这边写了两个是为了演示下 直接在html标签上面绑定ref拿到的就是dom。在组件上面拿到的是组件实例要$el一下onMounted(async () => {const data1 = await post(`/api/head`, { dom: head_dom.value })const data2 = await post(`/api/card`, { dom: card_dom.value.$el })})
</script>
下面简单解释下hooks代码中QSpin组件的代码。
<template><div v-show="visible" class="q-spin"><spin tip="加载中" /></div>
</template><script setup lang="ts">import { Spin } from 'ant-design-vue'import { ref } from 'vue'const visible = ref(false)const show = (dom: HTMLElement) => {visible.value = truedom.style.transform = dom.style.transform || `translate(0)`}defineExpose({ show })
</script><style scoped lang="less">.q-spin {position: fixed;z-index: 999;top: 0;bottom: 0;left: 0;right: 0;display: flex;flex-direction: column;justify-content: center;align-items: center;background-color: rgb(0 0 0 / 10%);}
</style>
这里是对antdv3的Spin组件做了一个简单的二次封装。主要讲解的就是一个loading覆盖传入dom的方法。
大多数地方使用的方式都是 relative 和 absolute 定位组合的方式,但是这里采用了transform 和 fixed定位组合的方式。因为我们的项目中可能出现这样一种情况
<div style="position: relative"><div ref="div_dom"><div style="position: absolute">我是内容</div></div></div>
假如 我们要给中间的的div添加loading, 使用relative 和 absolute 定位组合的方式。那么中间的div就会在样式表种添加一个position: relative的属性,这样代码就会变成这样
<div style="position: relative"><div style="position: relative" ref="div_dom"><div style="position: absolute">我是内容</div></div></div>
很明显 我们第三层div定位的根节点就从第一层变成了第二层,这样就会有可能导致我们样式的错乱。因此笔者采用了transform 和 fixed定位组合的方式。虽然上述的情况可能还会出现 但是会大大减少出现的可能性。
全局loading
这个就很简单了。如果你封装好了局部的loading 直接在配置项的dom中传入document.body 即可!
相关文章:
如何在 Axios 中去控制 Loading?大有学问!
目录 前言 按钮loading 局部loading 全局loading 前言 loading 的展示和取消可以说是每个前端对接口的时候都要关心的一个问题。这篇文章将要帮你解决的就是如何结合axios更加简洁的处理loading展示与取消的逻辑。 首先在我们平时处理业务的时候loading一般分为三种&#x…...
充电桩检测设备厂家TK4860C交流充电桩检定装置
TK4860系列是专门针对现有交流充电桩现场检测过程中接线复杂、负载笨重、现场检测效率低等问题而研制的一系列高效检测仪器,旨在更好的开展充电桩的强制检定工作。 充电桩检测设备是一款在交流充电桩充电过程中实时检测充电电量的标准仪器,仪器以新能源…...
一文3000字实现基于Selenium+Python的web自动化测试框架
一、什么是Selenium? Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台、跨浏览器的端到端的web自动化解决方案。Selenium主要包括三部分:Selenium IDE、Selenium WebDriver 和Selenium Grid。 Selenium IDE:Firefo…...
Android 12系统源码_窗口管理(二)WindowManager对窗口的管理过程
前言 上一篇我们具体分析了窗口管理者WindowManagerService的启动流程,对于WindowManagerService有了一个初步的认识。在此基础上,我本打算应该进一步分析WindowManagerService是如何管理系统中的各种窗口的,然而由于Android系统的架构设计,在分析WindowManagerService之前…...
python3.8,torch1.10.2+cu113、torch-geometric 安装
【1】conda create -n name python=3.8 【2】安装 torch 注意先看可适应的最高cuda版本 https://data.pyg.org/whl/ 版本对应 【3】按照顺序安装torch-geometric: torch-sparse、torch-scatter、torch-cluster、 torch-spline-conv \torch-geometric pip install torc…...
堆(heap)、栈(stack)
在程序中,栈和堆是两种非常重要的数据结构。它们都用来存储数据,但是它们的定义略有不同。 栈Stack: 栈是一种线性的数据结构,它以 “后进先出”(LIFO)的方式存储数据。栈中的内存空间在编译时就已经确定,大…...
企业级API网关之典型应用场景
目 录 01 企业面对API与网关的现状 02 APIGW介绍及企业应用场景 03 总结 01 企业面对API与网关的现状 在企业中,进行新的系统/应用/产品开发时,具有周密的流程:从需求分析、设计、开发、测试、发布与验收。所以,一…...
【2023年4月美赛加赛】Z题:The future of Olympics 25页完整论文
【2023年4月美赛加赛】Z题:The future of Olympics 25页完整论文 1 题目 背景 国际奥委会(IOC)正面临着夏季奥运会和冬季奥运会申办数量的减少**[1]**。在过去,举办奥运会的竞争非常激烈,声望也很高。然而,最近,主办…...
Rocket重试机制,消息模式,刷盘方式
一、Consumer 批量消费(推模式) Consumer端先启动 Consumer端后启动. 正常情况下:应该是Consumer需要先启动 consumer.setConsumeMessageBatchMaxSize(10);//每次拉取10条 package quickstart; import java.util.List; import co…...
linux+onenet可视化(图形化步骤)
文章目录 一、ONENET项目搭建1.1 ONENET注册1.2 创建产品与设备1.3 添加数据流 二、可视化配置 OneNET是由中国移动打造的PaaS物联网开放平台。平台能够帮助开发者轻松实现设备接入与设备连接,快速完成产品开发部署,为智能硬件、智能家居产品提供完善的物…...
汇编的基础
原视频 基础篇:1.1编程环境的安装 打开DOSBox 0.74-3 Options.bat调整窗口大小 windowresolution1200x640 outputddrawmount c D:\masm c: debugDEBUG 用Debug的R命令查看、改变CPU寄存器的内容: 用Debug的D命令查看内存中的内容: 用Debu…...
并发编程学习(十四):tomcat线程池
1、Tomcat 功能组件结构 Tomcat 的核心功能有两个,分别是负责接收和反馈外部请求的连接器 Connector,和负责处理请求的容器 Container。 其中连接器和容器相辅相成,一起构成了基本的 web 服务 Service。每个 Tomcat 服务器可以管理多个 Servi…...
简洁灵活工单管理系统,支持工单模版字段、工单状态自定义
一、开源项目简介 本项目为FeelDesk工单管理系统的开源版(OS),是基于开发者版(DEV)分离的标准版;支持工单模版字段、工单状态等自定义,可为不同的模版设置不同的路由规则;对工单需求…...
标签派单系统架构设计
需求描述 项目背景 根据员工历史成单情况,计算员工对不同类型工单的转化能力。根据员工和工单标签匹配进行派单。 业务流程图 规则描述 每10分钟,分城进行一次派单,派单规则可能会动态删减,需要支持动态配置 工单标签说明 一…...
Jmeter和Postman那个工具更适合做接口测试?
软件测试行业做功能测试和接口测试的人相对比较多。在测试工作中,有高手,自然也会有小白,但有一点我们无法否认,就是每一个高手都是从小白开始的,所以今天我们就来谈谈一大部分人在做的接口测试,小白变高手…...
k8s污点与容忍
1.前言 污点是给node节点打上污点标签,使得pod不能往该node节点上调度,污点有三种模式,分别是NoSchedule、PreferNoSchedule、NoExecute,容忍是给pod打上和node节点一样的污点标签,使pod能调度到带有该污点标签的node…...
市面上有哪些软件可以结合agentgpt的?众包平台结合的好处!
使用AgentGPT,提升工作效率! 随着科技的迅速发展,人工智能已经成为我们生活中不可或缺的一部分。而AgentGPT则是人工智能领域的一款杰出产品,它能够帮助我们提升工作效率,减少重复性劳动,让我们的生活更加便…...
【js】对象属性的拦截和Proxy代理与Reflect映射的用法与区别
✍️ 作者简介: 前端新手学习中。 💂 作者主页: 作者主页查看更多前端教学 🎓 专栏分享:css重难点教学 Node.js教学 从头开始学习 ajax学习 文章目录 对象属性的拦截介绍SetGet 对象的拦截介绍使用对象属性拦截和对象拦截区别练习题 映射…...
Yolov8涨点神器:ODConv+ConvNeXt提升小目标检测能力
1.涨点神器结合,助力YOLO 1.1 ICLR 2022涨点神器——即插即用的动态卷积ODConv 论文:Omni-Dimensional Dynamic Convolution 论文地址:Omni-Dimensional Dynamic Convolution | OpenReview ODConv通过并行策略引入一种多维注意力机制以对卷积核空间的四个维度学习更灵活的…...
git代码回滚是使用reset还是revert
时光不能回退,Git却允许我们改变历史。 想要让Git回退历史,有以下步骤: 使用git log命令,查看分支提交历史,确认需要回退的版本 使用git reset --hard commit_id命令,进行版本回退 使用git push origin命…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
