使用 Mock.js 模拟 API 数据,实现前后端并行开发
引言
在现代前端开发中,前后端分离已经成为标配。后端负责提供 API 接口,前端负责页面和交互。然而,在项目初期,后端接口往往还未就绪,前端开发不能因此阻塞。这时,我们可以在前端自己模拟(Mock)数据,让开发能够并行推进。Mock.js 就是一个非常实用的工具,它能帮助我们快速生成随机数据,并拦截 Ajax 请求,返回模拟的响应数据。
本文将以一个真实的代码示例(模拟文章列表接口)为线索,带你逐步掌握 Mock.js 的核心用法,并实现一个带有分页功能的模拟接口。
1. 为什么需要 Mock 数据?
- 前后端并行开发:前端不依赖后端接口进度,可独立开发和调试。
- 接口文档先行:前后端可以事先约定好接口数据结构,前端根据文档模拟数据,后端按照文档实现。
- 测试场景覆盖:轻松生成大量随机数据,方便测试列表、分页、异常情况等。
- 演示与原型:快速搭建可交互的原型,用于展示或评审。
2. 快速上手 Mock.js
2.1 安装
在项目中使用 npm 或 yarn 安装:
bash
npm install mockjs --save-dev
# 或
yarn add mockjs --dev
2.2 基本用法
Mock.js 提供了 Mock.mock() 方法,可以根据数据模板生成随机数据:
javascript
import Mock from 'mockjs'
const data = Mock.mock({
'list|5': [{
'id|+1': 1,
'name': '@cname'
}]
})
console.log(data)
// 输出:{ list: [ { id: 1, name: '张三' }, ... ] }
'list|5'表示生成一个数组,长度为 5。'id|+1'表示 id 每次自增 1。'@cname'是 Mock.js 内置的随机中文名。
有了初步印象后,我们开始构建一个更真实的场景。
3. Mock.js 语法详解:构建文章列表数据
假设我们需要模拟一个博客文章列表,每篇文章包含标题、简介、评论数、点赞数、发布时间、作者信息、标签、缩略图、图片列表以及唯一 ID。下面是完整的模拟数据生成代码(参考你提供的 posts.js):
javascript
import Mock from 'mockjs'
// 可选的标签列表
const tags = ['前端', '后端', '职场', 'AI', '副业', '面经', '算法']
const posts = Mock.mock({
// 生成 45 条文章数据
'list|45': [
{
title: '@ctitle(8,20)', // 随机中文标题,8-20个字符
brief: '@ctitle(20,100)', // 随机简介,20-100个字符
totalComment: '@integer(1,30)', // 评论数 1-30
totalLikes: '@integer(0,500)', // 点赞数 0-500
publishedAt: '@datetime("yyyy-MM-dd HH:mm:ss")', // 随机时间
// 嵌套的作者信息
user: {
id: '@integer(1,10)', // 用户ID 1-10
name: '@cname(2,4)', // 用户名 2-4个中文字符
avatar: '@image("300x200")', // 随机图片作为头像
},
// 标签:随机选取 2 个不同的标签
tags: () => Mock.Random.shuffle(tags).slice(0, 2),
thumbnail: '@image("300x200")', // 缩略图
pics: [ // 图片列表
'@image("300x200")',
'@image("300x200")',
'@image("300x200")',
],
id: '@increment(1)', // 自增 ID,从 1 开始
},
],
}).list
export default posts
3.1 常用占位符说明
| 占位符 | 说明 | 示例输出 |
|---|---|---|
@ctitle(min, max) |
随机中文标题 | "深入浅出前端工程化" |
@integer(min, max) |
随机整数 | 27 |
@datetime(format) |
随机日期时间 | "2023-08-15 14:23:09" |
@cname(min, max) |
随机中文名字 | "李小明" |
@image(size) |
随机图片占位(需网络请求) | "dummyimage.com/300x200" |
@increment(step) |
自增,step 为步长 | 1,2,3... |
() => Mock.Random.shuffle() |
自定义函数处理标签随机选取 |
⚠️ 注意 :
Mock.Random.pick(array)只能随机选取一个元素。要选取多个不同标签,可以像上面那样先shuffle再slice。
4. 模拟接口并实现分页
有了模拟数据后,下一步是拦截 Ajax 请求,返回分页后的数据。通常我们会创建一个 mock 文件夹,里面定义各个接口的响应逻辑。下面是模拟 /api/posts 接口的完整代码:
javascript
// mock/posts.js
import posts from './data/posts' // 上一步生成的 45 条文章数据
export default [
{
url: '/api/posts', // 接口地址
method: 'get', // 请求方法
response: ({ query }, res) => {
console.log(query, '//////')
// 1. 获取分页参数,并设置默认值
const { page = '1', limit = '10' } = query
const currentPage = parseInt(page, 10)
const size = parseInt(limit, 10)
// 2. 参数校验
if (isNaN(currentPage) || isNaN(size) || currentPage < 1 || size < 1) {
return {
code: 400,
msg: 'Invalid page or pageSize',
data: null,
}
}
// 3. 计算切片范围
const total = posts.length
const start = (currentPage - 1) * size
const end = start + size
const pageinatedData = posts.slice(start, end)
// 4. 返回成功响应
return {
code: 200,
msg: 'success',
data: pageinatedData,
pagination: {
current: currentPage,
limit: size,
total,
totalPage: Math.ceil(total / size),
},
}
},
},
]
4.1 代码解读
- 参数解析 :从
query对象中获取page和limit,并转换为数字类型。 - 边界处理 :若参数无效,返回
400错误码。 - 数据切片 :利用数组的
slice方法取出当前页的数据。 - 分页元数据 :返回
pagination对象,包含当前页、每页条数、总条数和总页数,方便前端渲染分页组件。
4.2 如何在项目中使用?
在实际项目中,你可以通过以下方式启用这些 Mock 接口:
- 使用
vite-plugin-mock:在 Vite 项目中配置插件,将上述数组传入即可自动拦截对应请求。 - 使用
webpack-dev-server的before钩子 :在devServer.before中注册中间件。 - 使用
Mock.mock拦截 XHR :Mock.js 本身可以拦截浏览器发出的 Ajax 请求,语法为Mock.mock(url, method, responseFn)。不过需要注意,这种方式会拦截所有符合规则的请求,适用于纯前端项目。
例如,用 Mock.js 原生拦截:
javascript
import Mock from 'mockjs'
import posts from './data/posts'
Mock.mock('/api/posts', 'get', (options) => {
// options 包含 url, type, body 等信息
const url = new URL(options.url, location.origin)
const page = url.searchParams.get('page') || '1'
const limit = url.searchParams.get('limit') || '10'
// ... 同上处理逻辑
})
5. 扩展:根据查询参数动态过滤数据
除了分页,实际接口往往还需要支持关键词搜索、标签筛选等功能。我们可以在 response 函数中进一步处理查询参数,动态过滤数据。
例如,增加按标题关键词搜索:
javascript
response: ({ query }) => {
const { page = '1', limit = '10', keyword = '' } = query
// ... 解析参数、校验
// 先过滤:如果有关键词,只保留标题包含关键词的文章
let filteredPosts = posts
if (keyword) {
filteredPosts = posts.filter(item => item.title.includes(keyword))
}
const total = filteredPosts.length
const start = (currentPage - 1) * size
const end = start + size
const pageinatedData = filteredPosts.slice(start, end)
return {
code: 200,
msg: 'success',
data: pageinatedData,
pagination: {
current: currentPage,
limit: size,
total,
totalPage: Math.ceil(total / size),
},
}
}
类似地,你还可以增加按标签筛选、按时间排序等功能,使得模拟接口更加贴近真实场景。
6. 结语
Mock.js 是一个非常轻量且强大的工具,它能帮助前端开发者在后端接口就绪前独立完成开发任务。通过本文的学习,你应该已经掌握了:
- Mock.js 的基本语法和常用占位符
- 如何生成复杂的嵌套数据
- 如何编写带分页功能的模拟接口
- 如何扩展过滤和搜索逻辑
当后端接口开发完成后,你只需要将 Mock 的接口定义注释掉,或者通过环境变量切换,就能无缝接入真实数据。这种模式不仅能提升开发效率,还能让团队协作更加顺畅。
希望本文能对你有所帮助,如果你在实践中有任何问题或心得,欢迎在评论区交流讨论!