封装按钮loading功能(非最终版)

1. 功能需求

在点击按钮请求接口的时候,不需要在处理函数内把loading改为true或false,而是识别请求的url,修改相对于loading的值。也就是说,当需要等待接口执行时,可以直接注册一个等待标志,而不是将流程内嵌到各种成功失败流程的处理代码中去。

2.大致思路

因为一个url对应一个loading,所以我希望能把这种对应关系存到一个数据里。新建一个waitHandleStore.ts文件,state里有loadingUrlObj,用于储存url和相对应loading的一一对应关系,声明两个方法,一个用于在请求拦截器和响应拦截器修改loading的值,一个用于往loadingUrlObj添加数据。

3.实现

3.1简化版

首先,state里声明loadingUrlObj,初始化为{};

往loadingUrlObj里添加数据:在组件文件里声明:btnLoding:fn(url),将url和btnLoading绑定起来,并且这个函数返回loading的状态。

在store文件里,fn(url)的实现写在这里。fn有两个功能:①往loadingUrlObj添加url和loading对应关系的数据;②返回当前url对应的loading的值。

在axios二次封装文件里,识别url,在请求拦截器里把相对应的loading值改为true,因为要包括错误处理,所以在请求的finally()里把loading改为false。

3.2详细版

waitHandleStore.ts里:
import { commonStoreShell } from '@/common/StoreShell';
import Vue from "vue";
import { CacherKeys } from "@/plugin/axios";

interface WaitHandleState {
    loadingUrlObj: object,
}

interface WaitHandleGetters {
}

/**
 * 此类专门用于提供各类等待标志,等待标的为特定接口
 * 也就是说,当需要等待接口执行时,可以直接从这里注册一个等待标志,而不是将流程内嵌到各种成功失败流程的处理代码中去
 * 因为等待是基于接口,故可以保证等待状态是正确的
 */
class WaitHandleStore extends commonStoreShell<WaitHandleState, WaitHandleGetters> {
    public getters = {
    }

    protected getStateInit(): WaitHandleState {
        return {
            // 结构:loadingUrlObj: {
            //					'/url': {
            // 						loading: true/false,
            //						seller: string //服务器名称
            //					}, ...
            //				}
            loadingUrlObj: {},
        }
    }
    // 修改url相对应loading的值
    public setLoadingObjVal(key: string, newVal: boolean) {
        this.state.loadingUrlObj[key].loading = newVal
    }
    // 新增url-loading,返回loading的值
    public getLoadingFlag(sellerSlot: CacherKeys, url: string) {
        if (!this.state.loadingUrlObj.hasOwnProperty(url)) {
            Vue.set(this.state.loadingUrlObj, url, { loading: false, seller: sellerSlot });
        }
        return this.state.loadingUrlObj[url].loading
    }

}

const waitHandle = new WaitHandleStore();

export { waitHandle };
axios二次封装文件里:
import { waitHandle } from '@/views/modules/waitHandleStore'

function createAxios(baseURL, cacherSlot: keyof typeof promiseCacher) {
  const instance = axios.create({
    baseURL,
    timeout: 1000 * 180,
    withCredentials: true
  })

  instance.interceptors.request.use(config => {
    // 请求拦截器识别到请求的url有注册过且服务器一致,改url对应loading为true(开始加载)
    if (waitHandle.state.loadingUrlObj.hasOwnProperty(config.url!) && cacherSlot === waitHandle.state.loadingUrlObj[config.url!].seller) {
      waitHandle.setLoadingObjVal(config.url!, true)
    }
    // 其他操作......
    return config
  }, error => {
    return Promise.reject(error)
  })

  instance.interceptors.response.use(response => {
      // ......
      return response.data;
    }
  }, error => {
    errorLog(error.message)
    return Promise.reject(error)
  })

  return {
    request<T = any>(config: AxiosRequestConfig & catcherExtraConfig): AxiosPromise<T> {
      const promise = instance.request(config).finally(() => {
        // 无论请求是否抛出错误,把loading改为false(停止加载)
        if (waitHandle.state.loadingUrlObj.hasOwnProperty(config.url!) && cacherSlot === waitHandle.state.loadingUrlObj[config.url!].seller) {
          waitHandle.setLoadingObjVal(config.url!, false)
        }
        // 其他操作......
      });

      return promise;
    },
  }
}

// axios主实例
const { request: service } = createAxios(process.env.VUE_APP_API, 'main');
// axios副实例
const { request: service_b2b } = createAxios(process.env.VUE_APP_API_B2B, 'b2b');
// axios副实例
const { request: service_seller } = createAxios(process.env.VUE_APP_API_SELLER, 'seller');

export default service;
export { service, service_b2b, service_seller };
使用:vue文件里
<template>
	<d2-container ref="container">
		<el-button :loading="loadingFlag && selStatus" @click="disable()">{{ t('input_stop') }}</el-button>
		<el-button :loading="loadingFlag && !selStatus" @click="enable()">{{ t('input_start') }}</el-button>
	</d2-container>
</template>

<script>
	import { waitHandle } from '../waitHandleStore'

	export default {
		computed: {
      // 注册url-loading
			loadingFlag() {
				return waitHandle.getLoadingFlag('main', '/ProductItem/updateStatus')
			},
		},
	};
</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Vue3中,我们可以使用`provide`和`inject`来实现全局loading封装。首先,在根组件中创建一个loading组件: ```vue <template> <div v-if="loading" class="loading-mask"> <div class="loading-spinner"></div> </div> <slot></slot> </template> <script> export default { data() { return { loading: false } }, methods: { show() { this.loading = true }, hide() { this.loading = false } } } </script> <style> .loading-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.7); display: flex; align-items: center; justify-content: center; z-index: 9999; } .loading-spinner { width: 40px; height: 40px; border: 3px solid #fff; border-top-color: #888; border-radius: 50%; animation: loading-spinner 0.8s linear infinite; } @keyframes loading-spinner { to { transform: rotate(360deg); } } </style> ``` 然后,在根组件中提供`loading`实例: ```vue <template> <loading v-slot="{ show, hide }"></loading> <router-view></router-view> </template> <script> import Loading from '@/components/Loading.vue' export default { provide: { loading: new Loading() } } </script> ``` 接下来,在需要使用loading的组件中使用`inject`注入`loading`实例,然后调用`show()`和`hide()`方法即可: ```vue <template> <div> <button @click="getData">加载数据</button> </div> </template> <script> export default { inject: ['loading'], methods: { async getData() { try { this.loading.show() // 请求数据 } catch (e) { console.error(e) } finally { this.loading.hide() } } } } </script> ``` 这样,我们就实现了一个简单的全局loading组件的封装

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值