Axios
简单使用
封装,然后调用。
js
import axios from 'axios';
// 创建 axios 实例
const http = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com', // 基础 URL
timeout: 10000, // 超时时间
});
// 请求拦截器
http.interceptors.request.use(
(config) => {
// 这里可以添加 token 等通用请求头
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
http.interceptors.response.use(
(response) => {
// 直接返回响应数据,简化调用
return response.data;
},
(error) => {
// 统一错误处理
console.error('请求失败:', error.message);
// 可以根据状态码进行特殊处理
if (error.response?.status === 401) {
// 未授权,跳转到登录页
console.error('未授权,请重新登录');
// router.push('/login');
}
return Promise.reject(error);
}
);
// 封装请求方法
export default {
// GET 请求
get(url, params = {}) {
return http.get(url, { params });
},
// POST 请求
post(url, data = {}) {
return http.post(url, data);
},
// PUT 请求
put(url, data = {}) {
return http.put(url, data);
},
// PATCH 请求
patch(url, data = {}) {
return http.patch(url, data);
},
// DELETE 请求
delete(url) {
return http.delete(url);
}
};js
import http from '@/utils/http';
// 用户相关 API
export const userApi = {
// 获取所有用户
getUsers() {
return http.get('/users');
},
// 获取单个用户
getUser(id) {
return http.get(`/users/${id}`);
},
// 创建用户
createUser(userData) {
return http.post('/users', userData);
},
// 更新用户
updateUser(id, userData) {
return http.put(`/users/${id}`, userData);
},
// 删除用户
deleteUser(id) {
return http.delete(`/users/${id}`);
}
};
// 帖子相关 API
export const postApi = {
// 获取所有帖子
getPosts() {
return http.get('/posts');
},
// 获取单个帖子
getPost(id) {
return http.get(`/posts/${id}`);
},
// 创建帖子
createPost(postData) {
return http.post('/posts', postData);
},
// 获取用户的帖子
getUserPosts(userId) {
return http.get('/posts', { params: { userId } });
}
};
// 评论相关 API
export const commentApi = {
// 获取帖子的评论
getPostComments(postId) {
return http.get('/comments', { params: { postId } });
}
};
// 导出所有 API
export default {
user: userApi,
post: postApi,
comment: commentApi
};vue
<template>
<div class="user-list">
<h2>用户列表</h2>
<!-- 加载状态 -->
<div v-if="loading" class="loading">
加载中...
</div>
<!-- 错误状态 -->
<div v-else-if="error" class="error">
加载失败: {{ error }}
</div>
<!-- 用户列表 -->
<div v-else class="user-cards">
<div
v-for="user in users"
:key="user.id"
class="user-card"
@click="selectUser(user)"
>
<h3>{{ user.name }}</h3>
<p>邮箱: {{ user.email }}</p>
<p>电话: {{ user.phone }}</p>
<p>公司: {{ user.company.name }}</p>
<button @click.stop="deleteUser(user.id)">删除</button>
</div>
</div>
<!-- 选中的用户详情 -->
<div v-if="selectedUser" class="user-detail">
<h3>用户详情</h3>
<p><strong>姓名:</strong> {{ selectedUser.name }}</p>
<p><strong>用户名:</strong> {{ selectedUser.username }}</p>
<p><strong>邮箱:</strong> {{ selectedUser.email }}</p>
<p><strong>地址:</strong> {{ selectedUser.address.city }}, {{ selectedUser.address.street }}</p>
<button @click="selectedUser = null">关闭</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { userApi } from '@/api/index';
// 响应式数据
const users = ref([]);
const loading = ref(true);
const error = ref(null);
const selectedUser = ref(null);
// 获取用户列表
const fetchUsers = async () => {
loading.value = true;
error.value = null;
try {
const data = await userApi.getUsers();
users.value = data;
} catch (err) {
error.value = err.message;
console.error('获取用户列表失败:', err);
} finally {
loading.value = false;
}
};
// 选择用户
const selectUser = async (user) => {
try {
// 获取用户详细信息
const userDetail = await userApi.getUser(user.id);
selectedUser.value = userDetail;
} catch (err) {
console.error('获取用户详情失败:', err);
}
};
// 删除用户
const deleteUser = async (id) => {
if (!confirm('确定要删除这个用户吗?')) return;
try {
await userApi.deleteUser(id);
// 从列表中移除
users.value = users.value.filter(user => user.id !== id);
console.log('用户删除成功');
} catch (err) {
console.error('删除用户失败:', err);
}
};
// 组件挂载时获取数据
onMounted(() => {
fetchUsers();
});
</script>
<style scoped>
.user-list {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.user-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}
.user-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
cursor: pointer;
transition: all 0.3s ease;
}
.user-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
background-color: #f9f9f9;
}
.user-card h3 {
margin: 0 0 10px 0;
color: #333;
}
.user-card p {
margin: 5px 0;
color: #666;
font-size: 14px;
}
.user-card button {
margin-top: 10px;
padding: 5px 10px;
background-color: #ff4757;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.loading, .error {
text-align: center;
padding: 40px;
font-size: 18px;
}
.error {
color: #ff4757;
}
.user-detail {
margin-top: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #f9f9f9;
}
.user-detail h3 {
margin-top: 0;
}
.user-detail p {
margin: 10px 0;
}
</style>vue
<template>
<div class="post-list">
<h2>帖子列表</h2>
<div class="controls">
<select v-model="selectedUserId" @change="fetchPosts">
<option value="">所有用户</option>
<option v-for="user in users" :key="user.id" :value="user.id">
{{ user.name }}
</option>
</select>
<button @click="showCreateForm = true">创建新帖子</button>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading">
加载中...
</div>
<!-- 错误状态 -->
<div v-else-if="error" class="error">
加载失败: {{ error }}
</div>
<!-- 帖子列表 -->
<div v-else class="posts">
<div v-for="post in posts" :key="post.id" class="post-card">
<h3>{{ post.title }}</h3>
<p>{{ post.body }}</p>
<p class="author">用户ID: {{ post.userId }}</p>
<button @click="fetchComments(post.id)">查看评论</button>
</div>
</div>
<!-- 创建帖子表单 -->
<div v-if="showCreateForm" class="modal">
<div class="modal-content">
<h3>创建新帖子</h3>
<form @submit.prevent="createPost">
<div class="form-group">
<label>标题:</label>
<input v-model="newPost.title" required>
</div>
<div class="form-group">
<label>内容:</label>
<textarea v-model="newPost.body" required rows="4"></textarea>
</div>
<div class="form-group">
<label>用户ID:</label>
<input v-model="newPost.userId" type="number" required>
</div>
<div class="form-actions">
<button type="submit">创建</button>
<button type="button" @click="showCreateForm = false">取消</button>
</div>
</form>
</div>
</div>
<!-- 评论列表 -->
<div v-if="comments.length > 0" class="comments">
<h3>评论</h3>
<div v-for="comment in comments" :key="comment.id" class="comment">
<p><strong>{{ comment.name }}</strong> ({{ comment.email }})</p>
<p>{{ comment.body }}</p>
</div>
<button @click="comments = []">关闭评论</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { userApi, postApi, commentApi } from '@/api/index';
// 响应式数据
const posts = ref([]);
const users = ref([]);
const comments = ref([]);
const loading = ref(true);
const error = ref(null);
const selectedUserId = ref('');
const showCreateForm = ref(false);
// 新帖子数据
const newPost = ref({
title: '',
body: '',
userId: 1
});
// 获取用户列表
const fetchUsers = async () => {
try {
const data = await userApi.getUsers();
users.value = data;
} catch (err) {
console.error('获取用户列表失败:', err);
}
};
// 获取帖子列表
const fetchPosts = async () => {
loading.value = true;
error.value = null;
try {
let data;
if (selectedUserId.value) {
data = await postApi.getUserPosts(selectedUserId.value);
} else {
data = await postApi.getPosts();
}
posts.value = data.slice(0, 10); // 只显示前10个
} catch (err) {
error.value = err.message;
console.error('获取帖子列表失败:', err);
} finally {
loading.value = false;
}
};
// 获取评论
const fetchComments = async (postId) => {
try {
const data = await commentApi.getPostComments(postId);
comments.value = data;
} catch (err) {
console.error('获取评论失败:', err);
}
};
// 创建新帖子
const createPost = async () => {
try {
await postApi.createPost(newPost.value);
alert('创建成功!');
showCreateForm.value = false;
// 清空表单
newPost.value = { title: '', body: '', userId: 1 };
// 刷新帖子列表
fetchPosts();
} catch (err) {
console.error('创建帖子失败:', err);
alert('创建失败!');
}
};
// 组件挂载时获取数据
onMounted(() => {
fetchUsers();
fetchPosts();
});
</script>
<style scoped>
.post-list {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.controls {
margin: 20px 0;
display: flex;
gap: 10px;
align-items: center;
}
.controls select {
padding: 8px;
border-radius: 4px;
border: 1px solid #ddd;
}
.controls button {
padding: 8px 16px;
background-color: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.posts {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}
.post-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
background-color: white;
}
.post-card h3 {
margin: 0 0 10px 0;
color: #333;
}
.post-card p {
margin: 10px 0;
color: #666;
}
.post-card .author {
font-size: 12px;
color: #999;
}
.post-card button {
margin-top: 10px;
padding: 5px 10px;
background-color: #2ed573;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.modal-content {
background-color: white;
padding: 30px;
border-radius: 8px;
min-width: 400px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.form-actions {
display: flex;
gap: 10px;
justify-content: flex-end;
margin-top: 20px;
}
.comments {
margin-top: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #f9f9f9;
}
.comment {
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.comment:last-child {
border-bottom: none;
}
.comment p {
margin: 5px 0;
}
</style>vue
<template>
<div id="app">
<header>
<h1>Vue 3 + Axios 示例</h1>
<nav>
<button @click="activeTab = 'users'">用户管理</button>
<button @click="activeTab = 'posts'">帖子管理</button>
</nav>
</header>
<main>
<div v-if="activeTab === 'users'">
<UserList />
</div>
<div v-else-if="activeTab === 'posts'">
<PostList />
</div>
</main>
</div>
</template>
<script setup>
import { ref } from 'vue';
import UserList from './components/UserList.vue';
import PostList from './components/PostList.vue';
// 当前激活的标签页
const activeTab = ref('users');
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
color: #333;
}
#app {
min-height: 100vh;
background-color: #f5f6fa;
}
header {
background-color: #2f3640;
color: white;
padding: 20px;
text-align: center;
}
header h1 {
margin-bottom: 20px;
}
header nav {
display: flex;
justify-content: center;
gap: 10px;
}
header button {
padding: 10px 20px;
background-color: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
header button:hover {
background-color: #2980b9;
}
main {
padding: 20px;
}
</style>