【底座】新增loading和request hook

This commit is contained in:
Shenlijun
2026-07-04 10:32:45 +08:00
committed by 小诺方舟
parent c28647b486
commit b94e159e74
2 changed files with 161 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
// useLoading.js
import { ref } from 'vue';
export function useLoading(name, initialValue = false) {
// 参数校验:name 必须是非空字符串
if (typeof name !== 'string' || !name.trim()) {
throw new Error('useLoading: first argument "name" must be a non-empty string');
}
const loading = ref(initialValue);
const capName = name.charAt(0).toUpperCase() + name.slice(1); // 首字母大写
const start = () => {
loading.value = true;
};
const stop = () => {
loading.value = false;
};
return {
[`${name}Loading`]: loading, // 动态命名:userLoading
[`start${capName}Loading`]: start, // 动态命名:startUserLoading
[`stop${capName}Loading`]: stop // 动态命名:stopUserLoading
};
}
/**
使用示例:
<template>
<div>
<!-- 直接使用动态生成的变量名 -->
<div v-if="userLoading" class="loading-indicator">用户数据加载中...</div>
<button
@click="handleFetch"
:disabled="userLoading"
>
{{ userLoading ? '加载中...' : '获取用户数据' }}
</button>
</div>
</template>
<script>
import { useLoading } from './useLoading';
import { fetchUserDataAPI } from '@/api';
export default {
setup() {
// 严格按您的要求调用:
// 第一个参数 = name ('user')
// 第二个参数 = initialValue (false)
const {
userLoading, // 响应式 loading 状态
startUserLoading, // 启动方法
stopUserLoading // 停止方法
} = useLoading('user', false);
// 手动控制 loading 状态
const handleFetch = async () => {
startUserLoading(); // 语义化启动
try {
await fetchUserDataAPI();
} catch (error) {
console.error('获取用户数据失败', error);
} finally {
stopUserLoading(); // 语义化停止
}
};
return {
userLoading,
handleFetch
};
}
};
</script>
*/
+79
View File
@@ -0,0 +1,79 @@
import { ref } from 'vue';
export function useRequest(name, service) {
// 参数校验(保持不变)
if (typeof name !== 'string' || !name.trim()) {
throw new Error('useRequest: first argument "name" must be a non-empty string');
}
if (typeof service !== 'function') {
throw new Error('useRequest: second argument "service" must be a function');
}
const data = ref(null);
const error = ref(null);
const loading = ref(false);
const capName = name.charAt(0).toUpperCase() + name.slice(1);
// ✅ 新增:纯 Promise 方法(不管理任何状态)
const runAsync = (...args) => {
return service(...args); // 直接返回原始 Promise
};
// ✅ 优化:基于 runAsync 实现 run(避免逻辑重复)
const run = async (...args) => {
loading.value = true;
error.value = null;
try {
const result = await runAsync(...args); // ← 复用 runAsync
data.value = result;
return result;
} catch (err) {
error.value = err;
throw err;
} finally {
loading.value = false;
}
};
return {
[`${name}Data`]: data,
[`${name}Error`]: error,
[`${name}Loading`]: loading,
[`fetch${capName}`]: run, // 自动管理状态
[`fetch${capName}Async`]: runAsync // 纯 Promise 模式
};
}
/*
✅ 测试用例 1:基础成功请求(run 模式)
const mockService = () => Promise.resolve({ id: 1, name: "Test User" });
// 初始化 hook
const { fetchUser, userData, userLoading, userError } =
useRequest('user', mockService);
// 触发请求
fetchUser();
// 验证结果
console.log(userLoading.value); // true → false (自动切换)
console.log(userData.value); // { id: 1, name: "Test User" }
console.log(userError.value); // null
✅ 测试用例 2:基础成功请求(runAsync 模式)
const { fetchUserAsync, userData, userLoading } =
useRequest('user', mockService);
// 仅执行请求,不修改内部状态
fetchUserAsync().then(result => {
console.log("Raw result:", result); // { id: 1, name: "Test User" }
// 关键验证:内部状态未被修改
console.log(userLoading.value); // false (始终为 false)
console.log(userData.value); // null (始终为 null)
});
*/