news 2026/5/10 15:58:17

FastAPI+VUE3创建一个项目的步骤模板(二)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FastAPI+VUE3创建一个项目的步骤模板(二)

接上文

修改VUE内容

打开文件 vue-frontend/src/App.vue,用以下代码替换其内容。我们使用浏览器的原生 fetch API 进行请求:

<script setup> import { ref, onMounted } from 'vue'; // ------------------------------------ // 1. 定义状态和常量 // ------------------------------------ const tasks = ref([]); // 存放从后端获取的任务列表 const newTaskTitle = ref(''); // 存储输入框的内容 const apiBaseUrl = 'http://127.0.0.1:8000'; // FastAPI 后端地址 // ------------------------------------ // 2. 获取任务的函数 (Read - 读取) // ------------------------------------ async function fetchTasks() { try { const response = await fetch(`${apiBaseUrl}/tasks`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } tasks.value = await response.json(); } catch (error) { console.error("获取任务失败:", error); alert('无法连接到 FastAPI 后端!请确保后端服务已运行在 http://127.0.0.1:8000'); } } // ------------------------------------ // 3. 增加新任务 (Create - 创建) // ------------------------------------ async function addTask() { if (!newTaskTitle.value.trim()) { alert('任务标题不能为空!'); return; } const taskData = { // ID 不需要提供,FastAPI 会自动分配 title: newTaskTitle.value, is_completed: false }; try { const response = await fetch(`${apiBaseUrl}/tasks`, { method: 'POST', // 使用 POST 方法 headers: { 'Content-Type': 'application/json', // 告诉后端我们发送的是 JSON }, body: JSON.stringify(taskData), // 将 JavaScript 对象转换为 JSON 字符串发送 }); if (response.ok) { const createdTask = await response.json(); tasks.value.push(createdTask); // 将新创建的任务(包含后端分配的ID)添加到前端列表 newTaskTitle.value = ''; // 清空输入框 } else { throw new Error('创建任务失败'); } } catch (error) { console.error("创建任务时发生错误:", error); alert('创建任务失败,请检查后端连接。'); } } // ------------------------------------ // 4. 切换任务完成状态 (Update - 更新) // ------------------------------------ async function toggleTask(task) { // 1. 立即在前端切换状态 (乐观更新) const newState = !task.is_completed; // 2. 准备发送给后端的数据 const updatedTaskData = { id: task.id, title: task.title, is_completed: newState // 发送新的状态 }; try { const response = await fetch(`${apiBaseUrl}/tasks/${task.id}`, { method: 'PUT', // 使用 PUT 方法进行全量更新 headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(updatedTaskData), }); if (response.ok) { // 3. 如果成功,更新本地状态 task.is_completed = newState; } else { // 4. 如果失败,回滚本地状态并报错 throw new Error(`更新任务状态失败, 状态码: ${response.status}`); } } catch (error) { console.error(`更新任务 ${task.id} 失败:`, error); alert('更新任务失败,请检查后端连接。'); // 如果请求失败,保持任务原有状态 } } // ------------------------------------ // 5. 删除任务 (Delete - 删除) // ------------------------------------ async function deleteTask(taskId) { if (!confirm('确定要删除这个任务吗?')) { return; } try { const response = await fetch(`${apiBaseUrl}/tasks/${taskId}`, { method: 'DELETE', // 使用 DELETE 方法 }); if (response.ok) { // 1. 如果后端删除成功,在前端列表中过滤掉该任务 tasks.value = tasks.value.filter(t => t.id !== taskId); } else { // 2. 如果后端返回 404 等,则抛出错误 throw new Error(`删除任务失败, 状态码: ${response.status}`); } } catch (error) { console.error(`删除任务 ${taskId} 失败:`, error); alert('删除任务失败,请检查后端连接。'); } } // ------------------------------------ // 6. 生命周期钩子 // ------------------------------------ // 组件挂载后立即调用 fetchTasks onMounted(fetchTasks); </script> <template> <div class="container"> <h1>📝 FastAPI & Vue 3 任务列表</h1> <div class="add-task-form"> <input type="text" v-model="newTaskTitle" @keyup.enter="addTask" placeholder="输入新的任务标题..." /> <button @click="addTask">添加任务</button> </div> <ul class="task-list" v-if="tasks.length"> <li v-for="task in tasks" :key="task.id" :class="{ completed: task.is_completed }"> <span class="title" @click="toggleTask(task)"> {{ task.title }} </span> <button class="delete-btn" @click="deleteTask(task.id)"> 删除 </button> </li> </ul> <p v-else class="empty-message"> 🎉 当前没有任务。快创建一个吧! </p> <p class="status-info"> 已成功连接到后端:**{{ apiBaseUrl }}** </p> </div> </template> <style> /* 样式部分保持一致性 */ body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f0f2f5; color: #333; } .container { max-width: 600px; margin: 50px auto; background: white; padding: 30px; border-radius: 12px; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); } h1 { text-align: center; color: #42b883; /* Vue 绿色 */ margin-bottom: 25px; } .add-task-form { display: flex; gap: 10px; margin-bottom: 25px; } .add-task-form input { flex-grow: 1; padding: 12px; border: 1px solid #ccc; border-radius: 6px; font-size: 16px; } .add-task-form button { background-color: #42b883; color: white; border: none; padding: 12px 20px; border-radius: 6px; cursor: pointer; white-space: nowrap; transition: background-color 0.2s; } .add-task-form button:hover { background-color: #369c6b; } .task-list { list-style: none; padding: 0; } .task-list li { display: flex; justify-content: space-between; align-items: center; padding: 12px 18px; margin-bottom: 10px; background: #fcfcfc; border-radius: 6px; border-left: 5px solid #42b883; transition: all 0.3s; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); } .task-list li.completed { opacity: 0.6; border-left-color: #aaa; background: #f4f4f4; } .title { cursor: pointer; flex-grow: 1; font-size: 1.1em; } .task-list li.completed .title { text-decoration: line-through; } .delete-btn { background-color: #ff4d4f; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer; transition: background-color 0.2s; } .delete-btn:hover { background-color: #d9363e; } .empty-message { text-align: center; padding: 20px; color: #666; font-style: italic; } .status-info { margin-top: 30px; padding-top: 15px; border-top: 1px solid #eee; font-size: 0.85em; text-align: center; color: #999; } </style>

将上面的内容替换原文件。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 20:36:30

Codebuddy使用CloudBase MCP辅助AI编码基于Spec工作流开发的坦克大战小游戏

目录引言一、什么是基于Spec的工作流二、基于Spec的工作流实现方式1、专为规范驱动设计的IDE2、集成规范驱动功能的工具或插件三、实践开发坦克大战小游戏1、IDE Codebuddy插件安装CloudBase MCP2、需求澄清3、技术方案设计4、任务分解5、技术实现总结引言 在上一篇文章《浅谈…

作者头像 李华
网站建设 2026/5/5 13:22:04

Java真的不行了,一天收到586份简历

这是小红书上一位招聘Java的人事发布的Java人员找工作现状。 Java以前有多火&#xff0c;现在就有多难挤进这条赛道&#xff0c;岗位越来越少&#xff0c;就业人越来越多&#xff0c;技术越来越新&#xff0c;时代越来越进步&#xff0c;这十分要求还在传统Java道路上的人&…

作者头像 李华
网站建设 2026/5/4 5:45:58

“N皇后”问题解法

C实现N皇后问题&#xff08;回溯法详解OJ适配&#xff09;一、核心问题分析不同行&#xff1a;由于每个皇后占一行&#xff0c;可简化为“逐行放置”&#xff08;每行仅放一个皇后&#xff09;不同列&#xff1a;同一列不能有两个皇后不同对角线&#xff1a;主对角线&#xff0…

作者头像 李华
网站建设 2026/5/10 1:50:05

Part 11|模块划分并非越细越好,关键在于明确职责边界

在明确要从业务边界开始拆系统之后&#xff0c;我很快遇到了一个新的现实问题&#xff1a;业务边界清楚了&#xff0c;但模块到底要拆到什么程度&#xff1f;一开始&#xff0c;我其实很容易走向一个极端&#xff1a; 既然要清晰&#xff0c;那就尽量拆细一点。 但真正把模块往…

作者头像 李华
网站建设 2026/5/8 0:52:48

设计模式之-观察者模式

1.先来看一个简单的例子 // 观察者 class Observer {update(data){// 观察者收到数据变化&#xff0c;自行处理要做的事情console.log(接收到了数据&#xff1a;--,data);} } // 目标 class Subject {constructor(){// 维护所有的观察者列表this.observers [];}add(ob){// 添…

作者头像 李华
网站建设 2026/5/9 21:24:49

单北斗GNSS在桥梁形变监测与维护中的应用与优势分析

本文旨在深度分析单北斗GNSS在桥梁形变监测与维护中的应用与优势。首先&#xff0c;单北斗GNSS厂家提供的各类产品&#xff0c;如变形监测一体机和传感器&#xff0c;具备独特的技术特性&#xff0c;能够满足不同桥梁监测需求。其次&#xff0c;监测系统的定制与实施方法&#…

作者头像 李华