proxy拦截请求,添加loading

本文介绍了如何在Vue3项目中通过 vuex 进行请求拦截和全局 loading 状态管理。首先,将所有请求模块集中管理,并使用 require.context 导入所有请求API,然后通过 Proxy 对象实现请求拦截,在每次请求开始和结束时更新 vuex 中的 loading 状态。同时,初始化所有loading状态并在组件中注入,以便在按钮等组件中动态显示加载状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果  每个请求都有自己独立loading 并统一在vuex内

1 request文件夹内放了所有的请求模块,将除了index和serveProxy文件内的请求全部拿出来,给他们做拦截,并且在vuex内配置loading状态

 

request /index  引入该文件,相当于引入当前目录一下所有请求api

// 集成所有请求
import serviceProxy  from './serveProxy.js'
// 一次引入所有函数
const requireAll = requireContext => requireContext.keys().map(requireContext)

/**
     * require.context(directory,useSubdirectories,regExp)
     * require.context():需要一次性的引入某个文件夹下的所有文件
        形参:
       directory:需要引入文件的目录 ./当前目录下面所有目录
       useSubdirectories:是否查找该目录下的子级目录 true
       regExp:匹配引入文件的正则表达式 
*/
const res = require.context('./', true, /^(?!\.\/(index|serviceProxy)).*\.js$/)

const checkUnique = (target, obj) => {
	Object.keys(obj).forEach(key => {
		if (key in target) {
			console.error(`存在重复键值 ${key}`)
		}
	})
} //检查要代理的请求是否重名,重名警告,需要重写配置名称
// requireAll(res) 读取目录下的文件内暴露的模块
// 0: Module
// saveInro: ƒ saveInro(data)
// Symbol(Symbol.toStringTag): "Module"

const service = requireAll(res).reduce((_service, module) => {
	//_service //上一次调用回调返回的值,或者是提供的初始值(initialValue)
	//module 当前正在被处理的值
	checkUnique(_service, module) //将上次的对象和当前正在处理的模块名称进行对比,是否重名
	return Object.assign(_service, module) //合并上次和本次的路径数据
}, {}) //初始数据为空对象
// service {'请求名':请求函数体,......}  处理的数据大致状态

// reduce 方法
// function(total,currentValue, index,arr) 第一个参数 函数
// total 初始值, 或者计算结束后的返回值 计算后的值 必须
// currentValue  当前元素 当前正在操作的值 必须
// currentIndex  当前索引 当前正在处理的值 可选
// arr           当前被操作元素所处的arr对象
// initialValue 第二个参数 传递给函数的初始值  可以是[]或者 {} //数据将遍历成数组或对象内
console.log(service)
export const getAjaxProps = () => Object.keys(service) //获取所有请求的键名称

export default serviceProxy(service, getAjaxProps()) //代理


request/serveProxy

 

// 请求拦截,将所有的请求统一集成在一起,并配置所有请求的状态
/**
 * serveAllObject 所有的请求对象  {string:()=>{},...}
 * serverAllKey  所有请求对象的键名  Array<string>
 */
import {store} from '@/store/index.js'
const serviceProxy = (serveAllObject, serverAllKey) => {
	return new Proxy(serveAllObject, {
		get(target, key) {
			//target当前正在被获取的对象  key 当前正在被获取对象的键
			if (!serverAllKey.includes(String(key))) return target[key] //检查是否存在键,不存在直接返回函数体
			const proxy = (...args) => {
				return new Promise(async (resolve, reject) => {
					store.commit('setloading', {
						//处理
						key, //要设置请求健名的状态
						status: true,
					})
					let result //请求结果
					let hasError = false //是否错误
					try {
						result = await target[key](...args)
					} catch (err) {
						result = err
						hasError = true
					}
					store.commit('setloading', {
						key,
						status: false,
					})
					hasError ? reject(result) : resolve(result)
				})
            }
            return proxy
		},
	})
}

export default serviceProxy

tool/tool

 

//初始化loading状态
export const initAllloadState = (app, store) => {
    const loading = getAjaxProps().reduce((res, key) => {
        res[key] = false
        return res
    }, {})
    // 初始化 loading 的状态
    console.log(isProxy(store.state.loading))
    store.commit('initloading', loading)
    app.provide(
        '$loading',
        computed(() => store.state.loading)
    )
}

main

import { store } from './store'
import { initAllloadState } from '@/tool/tool.js'
import { svginstall } from '@/icons/index.js'
svginstall(app) //全局安装svg组件
initAllloadState(app,store) //初始化loading状态

vuex

import { createStore } from 'vuex'

export const store = createStore({
	state() {
		return {
			count: 1,
			loading: {}, //所有需要拦截请求状态数据,键lbooler
		}
	},
	mutations: {
		//单独设置某个loading状态
		setloading(state, { key, status = false } = {}) {
			state.loading[key] = status
		},
		//初始化所有loading状态
		initloading(state, loading) {
			state.loading = loading
		},
	},
})

使用  可element-ui button 

template
<Button :loading="loading.test" @click.stop="handel"></Button>


js
import Button from '@/components/Button'
import Mobile from '@/components/Mobile'
import api from '@/request/index.js'
import { onMounted, inject } from 'vue'
import { usePie } from '@/tool/pie'
export default {
	components: {
		Button,
		Mobile,
	},
	setup(props) {
		const loading = inject('$loading') //获取所有loading的状态
		const handel = async () => {
			await api.test()
		}
		usePie('pie')
		return {
			handel,
			loading,
		}
	},
}
</script>

自己做button

<template>
	<div class="BTN" :style="{pointerEvents:loading?'none':'auto'}">
		<svg-icon iconClass="loading" :svgClass="svgClass" v-show="loading" :rotate='loading'></svg-icon>
        <span v-text='text'></span>
	</div>
</template>

<script>
import { computed } from 'vue'
export default {
	props: {
		loading: {
			type: Boolean,
			default: false,
        },
        text:{
            type:String,
            default:'More Details'
        }
	},
	setup(props) {
        const text=computed(()=>props.loading?'正在请求':props.text)
        return{
            text
        }
    },
}
</script>

感谢之前小伙伴留下来,今天研究了一了下,用vue3自己试了一下,很好

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值