前言
随着现代Web应用的发展,前后端分离架构已经成为主流开发模式。这种架构不仅提高了开发效率,还增强了系统的可维护性和扩展性。本文将带你从零开始,使用当下最热门的技术栈------FastAPI(Python后端框架)和Vue3(前端框架),搭建一个完整的前后端分离项目。
选择FastAPI作为后端框架是因为它具备高性能、易用性强、自动生成API文档等优势;而Vue3作为前端框架则以其响应式系统、组件化开发和优秀的开发体验著称。通过本文的学习,你将掌握完整的全栈开发流程,并为后续深入学习打下坚实基础。
技术栈介绍
- 后端技术栈 :
- FastAPI:现代、快速(高性能)的Python Web框架
- Python 3.8+
- uvicorn:ASGI服务器用于运行FastAPI应用
- 前端技术栈 :
- Vue3:渐进式JavaScript框架
- Vite:下一代前端构建工具
- vue-router:Vue.js官方路由管理器
- axios:基于Promise的HTTP客户端
我们将通过一个简单的任务管理系统示例,实现基本的增删改查(CRUD)功能,帮助你快速上手这套技术组合。
后端项目搭建
首先我们来创建FastAPI后端项目。创建一个新的目录并初始化项目:
注:默认是在Git Bash
上操作的
创建目录并进入目录
bash
# 创建目录
mkdir fastapi-vue3-demo
# 进入目录
cd fastapi-vue3-demo
创建虚拟环境
bash
python -m venv venv
激活虚拟环境
bash
# Windows
source venv\Scripts\activate
# Linux/Mac
source venv/bin/activate
安装fastapi依赖
bash
pip install "fastapi[standard]"
创建后端主文件backend/main.py
python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import uvicorn
app = FastAPI(title="Task Manager API", version="1.0.0")
# 数据模型定义
class Task(BaseModel):
id: Optional[int] = None
title: str
description: Optional[str] = None
completed: bool = False
# 模拟数据库(实际项目中应使用真实数据库)
tasks = [
Task(id=1, title="学习FastAPI", description="掌握FastAPI基础知识", completed=True),
Task(id=2, title="学习Vue3", description="了解Vue3 Composition API", completed=False)
]
next_id = 3
# API路由实现
@app.get("/")
async def root():
return {"message": "欢迎使用Task Manager API"}
@app.get("/tasks", response_model=List[Task])
async def get_tasks():
return tasks
@app.get("/tasks/{task_id}", response_model=Task)
async def get_task(task_id: int):
for task in tasks:
if task.id == task_id:
return task
raise HTTPException(status_code=404, detail="Task not found")
@app.post("/tasks", response_model=Task)
async def create_task(task: Task):
global next_id
task.id = next_id
next_id += 1
tasks.append(task)
return task
@app.put("/tasks/{task_id}", response_model=Task)
async def update_task(task_id: int, updated_task: Task):
for index, task in enumerate(tasks):
if task.id == task_id:
updated_task.id = task_id
tasks[index] = updated_task
return updated_task
raise HTTPException(status_code=404, detail="Task not found")
@app.delete("/tasks/{task_id}")
async def delete_task(task_id: int):
for index, task in enumerate(tasks):
if task.id == task_id:
tasks.pop(index)
return {"message": "Task deleted successfully"}
raise HTTPException(status_code=404, detail="Task not found")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
启动后端服务:
bash
uvicorn backend.main:app --reload
访问 http://localhost:8000/docs 查看自动生成的API文档。
前端项目搭建
接下来我们创建Vue3前端项目。确保已安装Node.js,然后执行:
创建前端项目
bash
npm create vite@latest frontend --template vue
进入前端项目
bash
cd frontend
安装默认依赖
bash
npm install
安装vue-router和axios
bash
npm install vue-router@4 axios
修改 frontend/src/main.js
添加路由支持:
javascript
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import Home from './components/Home.vue'
import TaskList from './components/TaskList.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/tasks', component: TaskList }
]
const router = createRouter({
history: createWebHistory(),
routes
})
createApp(App).use(router).mount('#app')
创建主页组件 frontend/src/components/Home.vue
:
vue
<template>
<div class="home">
<h1>欢迎使用任务管理系统</h1>
<p>这是一个使用FastAPI和Vue3构建的前后端分离应用</p>
<router-link to="/tasks">查看任务列表</router-link>
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
<style scoped>
.home {
text-align: center;
margin-top: 50px;
}
a {
display: inline-block;
margin-top: 20px;
padding: 10px 20px;
background-color: #42b983;
color: white;
text-decoration: none;
border-radius: 4px;
}
</style>
创建任务列表组件 frontend/src/components/TaskList.vue
:
vue
<template>
<div class="task-list">
<h1>任务列表</h1>
<div class="task-form">
<input v-model="newTask.title" placeholder="任务标题" />
<textarea v-model="newTask.description" placeholder="任务描述"></textarea>
<button @click="addTask">添加任务</button>
</div>
<div v-if="loading">加载中...</div>
<div v-else>
<div v-for="task in tasks" :key="task.id" class="task-item">
<h3>{{ task.title }}
<span :class="['status', {completed: task.completed}]">
{{ task.completed ? '已完成' : '未完成' }}
</span>
</h3>
<p>{{ task.description }}</p>
<div class="actions">
<button @click="toggleTask(task)" :class="{complete: !task.completed, undo: task.completed}">
{{ task.completed ? '撤销' : '完成' }}
</button>
<button @click="deleteTask(task.id)" class="delete">删除</button>
</div>
</div>
</div>
<div class="back-link">
<router-link to="/">返回首页</router-link>
</div>
</div>
</template>
<script>
import axios from 'axios'
const API_BASE_URL = 'http://localhost:8000'
export default {
name: 'TaskList',
data() {
return {
tasks: [],
newTask: {
title: '',
description: ''
},
loading: true
}
},
async mounted() {
await this.fetchTasks()
},
methods: {
async fetchTasks() {
try {
const response = await axios.get(`${API_BASE_URL}/tasks`)
this.tasks = response.data
this.loading = false
} catch (error) {
console.error('获取任务失败:', error)
this.loading = false
}
},
async addTask() {
if (!this.newTask.title.trim()) return
try {
const response = await axios.post(`${API_BASE_URL}/tasks`, this.newTask)
this.tasks.push(response.data)
this.newTask = { title: '', description: '' }
} catch (error) {
console.error('添加任务失败:', error)
}
},
async toggleTask(task) {
try {
const updatedTask = {
...task,
completed: !task.completed
}
await axios.put(`${API_BASE_URL}/tasks/${task.id}`, updatedTask)
task.completed = !task.completed
} catch (error) {
console.error('更新任务失败:', error)
}
},
async deleteTask(id) {
try {
await axios.delete(`${API_BASE_URL}/tasks/${id}`)
this.tasks = this.tasks.filter(task => task.id !== id)
} catch (error) {
console.error('删除任务失败:', error)
}
}
}
}
</script>
<style scoped>
.task-list {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.task-form {
margin-bottom: 30px;
padding: 20px;
background-color: #f5f5f5;
border-radius: 4px;
}
.task-form input,
.task-form textarea {
width: 100%;
margin-bottom: 10px;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.task-form button {
background-color: #42b983;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
}
.task-item {
border: 1px solid #ddd;
padding: 15px;
margin-bottom: 15px;
border-radius: 4px;
}
.status {
font-size: 0.8em;
padding: 2px 6px;
border-radius: 4px;
background-color: #f0ad4e;
color: white;
}
.status.completed {
background-color: #5cb85c;
}
.actions {
margin-top: 10px;
}
.actions button {
margin-right: 10px;
padding: 5px 10px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.complete {
background-color: #5cb85c;
color: white;
}
.undo {
background-color: #f0ad4e;
color: white;
}
.delete {
background-color: #d9534f;
color: white;
}
.back-link {
margin-top: 20px;
}
.back-link a {
color: #42b983;
text-decoration: none;
}
</style>
更新 frontend/src/App.vue
:
vue
<template>
<div id="app">
<nav>
<router-link to="/">首页</router-link> |
<router-link to="/tasks">任务管理</router-link>
</nav>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
启动前端开发服务器:
bash
cd frontend
npm run dev
解决跨域问题
由于前后端分别运行在不同端口(前端5173,后端8000),我们需要解决跨域问题。修改后端 backend/main.py
添加CORS支持:
python
from fastapi.middleware.cors import CORSMiddleware
# 添加CORS中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"], # Vite默认端口
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
重新启动后端服务即可。
总结与展望
通过本文的学习,我们成功搭建了一个完整的FastAPI + Vue3前后端分离项目,实现了基本的CRUD功能。这个项目虽然简单,但它为你提供了以下几个重要知识点:
- FastAPI后端开发:包括路由定义、数据模型验证、异常处理等
- Vue3前端开发:使用Composition API、组件化开发、路由管理等
- 前后端交互:通过RESTful API进行数据交换
- 开发环境配置:项目结构规划、依赖管理等
这只是全栈开发的第一步,后续你可以在此基础上:
- 集成数据库(如SQLite、PostgreSQL等)
- 添加用户认证和权限管理
- 实现更复杂的业务逻辑
- 部署到生产环境
- 添加单元测试和集成测试
如果你想深入了解这些技术栈的更多高级特性,欢迎关注我们的系列视频教程,我们将从基础到进阶,一步步带你成为全栈开发高手!
作者简介:专注于Python和前端技术分享,致力于帮助开发者快速掌握现代Web开发技能。
查看更多教程,小破站搜:mldong666
希望这篇文章对你有所帮助!如果有任何问题或建议,欢迎在评论区留言交流。