1.创建 useAxios.ts 文件:
创建一个 TypeScript 版本的 useAxios.ts 文件,并添加类型注解。
// useAxios.ts
import { ref } from 'vue';
import axios, { AxiosInstance, AxiosResponse, AxiosRequestConfig } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
import router from './router'; // 导入 Vue Router
interface UseAxiosResponse<T> {
loading: Ref<boolean>;
error: Ref<Error | null>;
data: Ref<T | null>;
fetchData: (url: string, config?: AxiosRequestConfig) => Promise<void>;
}
export function useAxios<T = any>(): UseAxiosResponse<T> {
const loading = ref(false);
const error = ref<Error | null>(null);
const data = ref<T | null>(null);
const instance: AxiosInstance = axios.create({
baseURL: 'https://api.example.com', // 根据您的 API 设置
timeout: 5000, // 请求超时时间
});
instance.interceptors.request.use(
(config: AxiosRequestConfig) => {
loading.value = true;
error.value = null;
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error: Error) => {
return Promise.reject(error);
}
);
instance.interceptors.response.use(
(response: AxiosResponse) => {
loading.value = false;
data.value = response.data;
return response;
},
(error: Error) => {
loading.value = false;
error.value = error;
if (error.response) {
const status = error.response.status;
if (status === 401) {
ElMessageBox.confirm('登录已过期,请重新登录', '提示', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
router.push('/login'); // 导航到登录页面
}).catch(() => {
// 用户点击取消按钮后的处理
});
} else if (status === 403) {
ElMessage.error('无权限访问该资源');
} else if (status === 500) {
ElMessage.error('服务器出错,请稍后重试');
} else if (status === 405) {
ElMessage.error('请求方法不允许');
}
}
return Promise.reject(error);
}
);
const fetchData = async (url: string, config: AxiosRequestConfig = {}): Promise<void> => {
loading.value = true;
error.value = null;
try {
const response = await instance.get(url, config);
data.value = response.data;
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
};
return {
loading,
error,
data,
fetchData,
};
}
2.创建hook 组件:
在 Vue 组件中,添加 TypeScript 类型注解,并使用 ref 函数定义响应式变量的类型
<template>
<div>
<div v-if="loading">Loading...</div>
<div v-else-if="error">{{ error.message }}</div>
<div v-else>{{ data }}</div>
</div>
</template>
<script lang="ts">
import { ref, onMounted, Ref } from 'vue';
import { useAxios } from '@/useAxios';
export default {
setup() {
const { loading, error, data, fetchData }: {
loading: Ref<boolean>;
error: Ref<Error | null>;
data: Ref<any | null>;
fetchData: (url: string) => Promise<void>;
} = useAxios();
// 在组件加载时立即发起接口请求
onMounted(() => {
fetchData('/api/data'); // 传入要请求的接口 URL
});
return {
loading,
error,
data,
};
},
};
</script>