方法1:hook.ts
import { Ref, ref } from 'vue';
type TApiFun<TData, TParams extends Array<any>> = (...params: TParams) => Promise<TData>;
interface AutoRequestOptions {
// 定义一下初始状态
loading?: boolean;
// 接口调用成功时的回调
onSuccess?: (data: any) => void;
}
type AutoRequestResult<TData, TParams extends Array<any>> = [Ref<boolean>, TApiFun<TData, TParams>];
/* 控制loading状态的自动切换hook */
export function useAutoRequest<TData, TParams extends any[] = any[]>(fun: TApiFun<TData, TParams>, options?: AutoRequestOptions): AutoRequestResult<TData, TParams> {
const { loading = false, onSuccess } = options || { loading: false };
const requestLoading = ref(loading);
const run: TApiFun<TData, TParams> = (...params) => {
requestLoading.value = true;
return fun(...params)
.then((res) => {
onSuccess && onSuccess(res);
return res;
})
.finally(() => {
requestLoading.value = false;
});
};
return [requestLoading, run];
}
api/index.ts
export function submitApi(text: string) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟接口调用有概率出错
if (Math.random() > 0.5) {
resolve({
status: "ok",
text: text,
});
} else {
reject(new Error("不小心出错了!"));
}
}, 3000);
});
}
使用:index.vue
<script setup name="Index" lang="ts">
import { useAutoRequest } from "./hook";
import { Button } from "ant-design-vue";
import { submitApi } from "@/api";
const [loading, submit] = useAutoRequest(submitApi);
function onSubmit() {
submit("aaa").then((res) => {
console.log("res", res);
});
}
</script>
<template>
<div class="col">
<Button :loading="loading" @click="onSubmit">提交</Button>
</div>
</template>
方法2:hook2.ts
import type { Ref } from "vue";
import { ref } from "vue";
type AutoLoadingResult = [
Ref<boolean>,
<T>(requestPromise: Promise<T>) => Promise<T>
];
/* 在给run方法传入一个promise,会在promise执行前或执行后将loading状态设为true,在执行完成后设为false */
export function useAutoLoading(defaultLoading = false): AutoLoadingResult {
const ld = ref(defaultLoading);
function run<T>(requestPromise: Promise<T>): Promise<T> {
ld.value = true;
return requestPromise.finally(() => {
ld.value = false;
});
}
return [ld, run];
}
使用:
<script setup name="Index" lang="ts">
// import { useAutoRequest } from "./hook";
import { useAutoLoading } from "./hook2";
import { Button } from "ant-design-vue";
import { submitApi, cancelApi } from "@/api";
// const [loading, submit] = useAutoRequest(submitApi);
const [commonLoading, fetch] = useAutoLoading();
function onSubmit() {
fetch(submitApi("submit")).then((res) => {
console.log("res", res);
});
}
function onCancel() {
fetch(cancelApi("cancel")).then((res) => {
console.log("res", res);
});
}
</script>
<template>
<div class="col">
<Button type="primary" :loading="commonLoading" @click="onSubmit">
提交
</Button>
<Button :loading="commonLoading" @click="onCancel">取消</Button>
</div>
</template>