2-4 首页项目Mock开发工作流回顾
前端 Mock 开发工作流全景
在实际项目开发中,前后端并行开发是提升团队效率的关键策略。Mock 开发工作流的核心思路是:前端在不依赖后端接口的前提下,通过模拟数据完成页面开发与交互逻辑,待后端接口就绪后无缝切换到真实数据源。
标准开发流程
需求分析 → 接口定义(根据原型设计响应数据结构与类型)
→ 页面样式开发(框架 + CSS 组件库快速实现)
→ Mock 数据对接 → 前端开发完成
→ 环境切换(.env.development 配置真实 API 地址)
→ 联调测试 → 交付
text
Mock 接口 vs 页面内写死数据
| 对比维度 | Mock 接口服务 | 页面内硬编码数据 |
|---|---|---|
| 数据形态 | 模拟真实 HTTP 请求(本地 Node.js 服务) | 静态 JSON 对象 |
| 动态数据 | 支持随机生成、分页、筛选等动态场景 | 需手动维护 |
| 交互模拟 | 可模拟加载状态、错误状态、网络延迟 | 无法模拟 |
| 代码侵入 | 零侵入,环境变量切换即可 | 散落在各组件中,清理成本高 |
| 团队协作 | 接口定义与页面开发解耦 | 数据与视图强耦合 |
环境切换方案
通过 Vite 的环境变量机制实现 Mock 与真实接口的无缝切换:
// .env.development(开发环境 - 使用 Mock)
VITE_API_BASE_URL=http://localhost:3001/mock
// .env.staging(测试环境 - 使用测试服务器)
VITE_API_BASE_URL=https://api-staging.example.com
// .env.production(生产环境)
VITE_API_BASE_URL=https://api.example.com
typescript
// src/utils/request.ts
import axios from 'axios'
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
})
request.interceptors.response.use(
(response) => response.data,
(error) => {
console.error('请求错误:', error.message)
return Promise.reject(error)
}
)
export default request
typescript
MSW(Mock Service Worker)现代方案
相比传统的 Mock.js 或 json-server,MSW 是当前业界推荐的 API Mock 方案。它在 Service Worker 层拦截请求,无需修改任何业务代码:
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw'
export const handlers = [
// 获取课程列表
http.get('/api/courses', ({ request }) => {
const url = new URL(request.url)
const page = Number(url.searchParams.get('page') || 1)
const pageSize = Number(url.searchParams.get('pageSize') || 10)
return HttpResponse.json({
code: 200,
data: {
list: Array.from({ length: pageSize }, (_, i) => ({
id: (page - 1) * pageSize + i + 1,
title: `课程标题 ${(page - 1) * pageSize + i + 1}`,
cover: `https://picsum.photos/300/200?random=${i}`,
price: (Math.random() * 200 + 50).toFixed(2),
category: ['前端', '后端', '全栈'][Math.floor(Math.random() * 3)],
})),
total: 100,
page,
pageSize,
},
})
}),
// 获取课程详情
http.get('/api/courses/:id', ({ params }) => {
return HttpResponse.json({
code: 200,
data: {
id: params.id,
title: 'Vue3 + TypeScript 企业级实战',
description: '从零到一构建大型前端项目',
chapters: [
{ id: 1, title: '项目初始化', duration: 45 },
{ id: 2, title: '路由与状态管理', duration: 60 },
{ id: 3, title: '组件设计模式', duration: 55 },
],
},
})
}),
]
typescript
// src/mocks/browser.ts
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)
typescript
// src/main.ts — 条件启用 Mock
import { createApp } from 'vue'
import App from './App.vue'
async function bootstrap() {
// 仅在开发环境启用 Mock
if (import.meta.env.DEV) {
const { worker } = await import('./mocks/browser')
await worker.start({ onUnhandledRequest: 'bypass' })
}
createApp(App).mount('#app')
}
bootstrap()
typescript
数据管理最佳实践
接口数据统一在 Store(状态管理)中管理,而非散落在各组件内:
// src/stores/course.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import request from '@/utils/request'
export const useCourseStore = defineStore('course', () => {
const courseList = ref<CourseItem[]>([])
const loading = ref(false)
const total = ref(0)
// 计算属性 — 数据加工逻辑集中管理
const affordableCourses = computed(() =>
courseList.value.filter((c) => Number(c.price) < 100)
)
const averagePrice = computed(() => {
if (courseList.value.length === 0) return 0
const sum = courseList.value.reduce((acc, c) => acc + Number(c.price), 0)
return (sum / courseList.value.length).toFixed(2)
})
async function fetchCourses(page = 1, pageSize = 10) {
loading.value = true
try {
const res = await request.get('/api/courses', {
params: { page, pageSize },
})
courseList.value = res.data.list
total.value = res.data.total
} finally {
loading.value = false
}
}
return { courseList, loading, total, affordableCourses, averagePrice, fetchCourses }
})
typescript
将数据集中在 Store 中管理的核心原因:
- 跨页面复用 — 多个页面可共享同一份数据和计算逻辑
- 数据处理集中化 — 数据转换、计算、过滤等逻辑统一定义
- 状态可追踪 — 数据变更路径清晰,便于调试和维护
- 缓存控制 — 避免重复请求,提升性能
关键要点
- Mock 接口模拟的是真实 HTTP 请求,能验证完整的前端交互链路
- 环境变量
.env.*文件实现 Mock 到真实接口的零代码切换 - 接口定义统一管理在
api/目录,数据存储统一在store/中 - MSW 是当前最推荐的 Mock 方案,基于 Service Worker 层拦截,不侵入业务代码
- Store 集中管理数据和处理逻辑,是保证代码可维护性的关键设计决策
↑