Skip to content

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>