怎么使用 Mock.js 生成嵌套对象、数组及自定义随机数据
深入讲解如何使用 Mock.js 的数据模板语法(DTD)生成深层嵌套对象、指定长度或区间的动态数组,并通过 Mock.Random 扩展自定义业务格式的随机数据。
在前后端分离的开发流程中,前端常因后端接口尚未就绪而无法推进联调。使用 Mock.js 可以通过声明“数据模板(Data Template Definition,简称 DTD)”和内置的“随机占位符(Mock.Random)”,完全脱离真实服务端,本地模拟出贴近真实业务的多层级嵌套对象、特定长度范围的数组以及符合业务规范的定制随机数据。
一、Mock.js 的核心语法机制与接入步骤
Mock.js 的核心思想是“在属性名中定义生成规则,在属性值中提供基础样本或占位符”。其标准声明格式遵循以下结构:
'name|rule': value
其中,name 是输出 JSON 中的目标键名;|rule 是生成规则,负责控制生成对象的子项数量、数组长度或数值范围;value 则是模版初值,可以包含具体的字面量、内嵌的子模板,或者是带 @ 前缀的随机数据占位符。
实现一套包含复杂对象、数组和自定义规则的数据模拟,通常遵循标准化的四步接入流程:
二、生成层级嵌套对象
在复杂的管理后台或微服务接口中,响应通常由外层的通用包头和深层嵌套的领域数据组成。Mock.js 支持在对象内部无限递归定义下级对象,同时也能控制属性的抽取行为。
1. 对象的两种核心生成规则
'name|count': object:从后面的object中随机选择count个属性。'name|min-max': object:从后面的object中随机选择min到max个属性。- 常规嵌套(无管道符):直接使用
'name': { ... }。此时 Mock.js 会原样保持该对象的层级,并继续递归处理其内部子属性的生成规则。
2. 多层级嵌套对象代码示例
以下示例构造一个典型的用户详情响应,包含账号信息、嵌套的组织与部门信息、以及用户的偏好配置:
// 引入 Mock.js
const Mock = require('mockjs');
// 定义多层嵌套对象模板
const template = {
code: 200,
message: '操作成功',
data: {
// 基础信息层
userId: '@guid',
username: '@word(6, 12)',
// 嵌套个人资料对象
profile: {
realName: '@cname',
avatar: "@image('100x100', '#345E82', '#ffffff', 'Avatar')",
age: '@integer(22, 60)',
// 进一步嵌套地理位置对象
location: {
province: '@province',
city: '@city',
address: '@county(true) @cword(3, 8)号'
}
},
// 嵌套权限与偏好对象(从 4 个可选配置中随机选 2 个生效)
'preferences|2': {
darkMode: '@boolean',
emailNotification: '@boolean',
smsNotification: '@boolean',
autoSave: '@boolean'
}
}
};
const result = Mock.mock(template);
console.log(JSON.stringify(result, null, 2));
在这个结构中,data.profile.location 实现了深达四层的层级嵌套,而 preferences|2 会在给定的四个偏好项中随机筛选保留两个,既模拟了层级深度,又保留了属性的动态随机性。
三、生成动态长度与重复规则的数组
在列表查询、表格分页或批量操作接口中,数组是最基础的数据载体。Mock.js 针对数组提供了极为灵活的重复规则与项抽取规则。
1. 数组语法规则对照
| 语法声明 | 规则类型 | 含义与生成结果 |
|---|---|---|
'list|5': [item] |
固定重复 | 将 item 模板重复 5 次,生成包含 5 个元素的数组。 |
'list|3-8': [item] |
区间随机重复 | 将 item 模板重复 3 到 8 次,用于测试不同数据量下的前端列表渲染。 |
'target|1': ['A', 'B', 'C'] |
单项抽取 | 从提供的候选元素中,随机选取 1 个元素作为最终值输出。 |
'target|+1': ['A', 'B', 'C'] |
顺序轮播抽取 | 从候选列表中按索引依次递增取值(常用于列表中每条数据的状态顺序变化)。 |
2. 嵌套数组实战示例:表格分页数据
在实际开发中,数组的每一项往往都是一个包含丰富字段的复杂对象,甚至数组项内部又嵌套包含着子数组(如文章列表及每篇文章的标签数组):
const Mock = require('mockjs');
const articleListTemplate = {
code: 200,
data: {
total: 50,
page: 1,
pageSize: 10,
// 生成 5 到 10 条文章记录
'records|5-10': [
{
'id|+1': 1001, // 循环递增 ID
title: '@ctitle(8, 20)', // 中文文章标题
summary: '@cparagraph(1, 3)', // 中文段落摘要
viewCount: '@integer(100, 5000)',
isTop: '@boolean',
publishTime: '@datetime("yyyy-MM-dd HH:mm:ss")',
// 数组内部嵌套数组:每篇文章随机分配 1 到 4 个标签
'tags|1-4': [
'@cword(2, 4)'
],
// 数组内部嵌套对象:作者信息
author: {
uid: '@guid',
name: '@cname',
'role|1': ['Admin', 'Editor', 'Author'] // 随机抽取 1 个角色
}
}
]
}
};
const mockData = Mock.mock(articleListTemplate);
console.log(mockData);
'list|count': [item] 时,如果 item 是一个普通字面量(例如数字或字符串),生成的只是简单数组;如果 item 是包含占位符的对象,Mock.js 会在每一次迭代生成时重新执行一次占位符计算,因此每个数组元素中的 id、title 和 author 都是彼此独立且互不相同的。
四、使用内置占位符与扩展自定义随机数据
Mock.js 内部提供了一个强大的工具类 Mock.Random。在数据模板中,只要在字符串属性值前加上 @ 符号,Mock.js 就会将其识别为占位符并调用对应的生成函数。
1. 常用内置占位符快速分类
- 文本与名称:
@cname(中文姓名)、@ctitle(3, 8)(中文标题)、@cparagraph(中文段落)。 - 数字与时间:
@integer(1, 100)(整数)、@float(10, 100, 2, 4)(浮点数)、@date('yyyy-MM-dd')、@now()。 - 网络与标识:
@guid(全局唯一标识)、@ip(IP 地址)、@url(完整 URL)、@email(邮箱)。 - 地理与区域:
@province、@city、@county(true)(带省市前缀的县区)。
2. 使用 Random.extend 扩展业务特定随机数据
真实项目通常需要符合特定业务规范的数据,比如统一社会信用代码、特定格式的内部订单号(如 ORD-20261030-XXXX)、特定加密哈希或身份证号。此时可以使用 Mock.Random.extend() 注册自定义方法:
const Mock = require('mockjs');
const Random = Mock.Random;
// 1. 注册自定义随机函数
Random.extend({
// 自定义业务订单流水号: 业务前缀 + 年月日 + 6位随机序列
bizOrderSn: function() {
const prefix = 'ORD';
const dateStr = Mock.mock('@date("yyyyMMdd")');
const randomSuffix = Mock.mock('@string("number", 6)');
return `${prefix}-${dateStr}-${randomSuffix}`;
},
// 自定义手机号码生成器(符合国内常见号段规范)
mobilePhone: function() {
const prefixes = ['138', '139', '150', '188', '199', '177'];
const prefix = this.pick(prefixes);
const suffix = Mock.mock('@string("number", 8)');
return `${prefix}${suffix}`;
},
// 自定义行业状态码与描述
bizStatus: function() {
const statuses = [
{ code: 1001, text: '待审核' },
{ code: 1002, text: '流转中' },
{ code: 2000, text: '已归档' },
{ code: 5000, text: '异常挂起' }
];
return this.pick(statuses);
}
});
// 2. 在模板中直接通过 @函数名 调用
const orderResponse = Mock.mock({
code: 200,
data: {
orderNo: '@bizOrderSn', // 调用自定义扩展
contactMobile: '@mobilePhone', // 调用自定义扩展
statusInfo: '@bizStatus', // 调用自定义对象抽取
createTime: '@datetime'
}
});
console.log(orderResponse);
扩展方法执行时,其内部 this 指向 Mock.Random 实例,因此可以直接复用 this.pick()、this.natural() 等原生方法,从而保持代码的紧凑与规范。
五、综合实战:构建多层级、带数组与自定义规则的完整 API
结合前面介绍的嵌套对象、动态数组以及自定义随机数据,我们来构造一个完整的电商订单分页响应,并使用 Mock.mock() 拦截前端发出的异步请求。
import Mock from 'mockjs';
// 步骤 1:注册业务所需的自定义随机算法
Mock.Random.extend({
skuCode: function() {
return 'SKU-' + Mock.mock('@string("upper", 4)') + '-' + Mock.mock('@string("number", 4)');
}
});
// 步骤 2:定义综合响应模板
const apiTemplate = {
status: 'SUCCESS',
timestamp: '@now("T")',
data: {
pagination: {
currentPage: 1,
pageSize: 10,
totalCount: 100,
totalPages: 10
},
// 生成包含 3 到 6 个订单项的数组
'orders|3-6': [
{
orderId: '@guid',
orderSn: '@bizOrderSn', // 自定义扩展
status: '@bizStatus', // 自定义扩展
// 嵌套买家对象
buyer: {
uid: '@integer(10000, 99999)',
nickname: '@cname',
phone: '@mobilePhone',
deliveryAddress: {
province: '@province',
city: '@city',
detail: '@county(true) @cword(4, 10)'
}
},
// 订单内嵌套商品列表(1 到 3 种商品)
'goodsList|1-3': [
{
sku: '@skuCode',
name: '@ctitle(4, 10)',
'price|10-500.2': 1, // 生成 10 到 500 之间,带 2 位小数的数字
quantity: '@integer(1, 5)',
thumbnail: "@image('120x120', '#345E82', '#ffffff', 'Goods')"
}
],
// 支付明细嵌套
payment: {
'channel|1': ['ALIPAY', 'WECHAT_PAY', 'UNION_PAY'],
payTime: '@datetime',
isInvoiceIssued: '@boolean'
}
}
]
}
};
// 步骤 3:拦截前端请求 URL 并返回模拟数据
// 拦截形如 /api/v1/orders 的 GET 或 POST 请求
Mock.mock(RegExp('/api/v1/orders.*'), 'get', (options) => {
console.log('接收到请求:', options.url);
// 执行生成并返回标准 JSON
return Mock.mock(apiTemplate);
});
六、关键注意事项与工程化总结
在长期项目和团队开发中应用 Mock.js 时,需要注意以下边界条件和避坑事项:
- 占位符引用作用域:占位符(如
@cname)只能出现在字符串值中。如果写成name: @cname(未加引号),会导致 JavaScript 语法解析错误。必须以字符串形式提供:name: '@cname'。 - 数值型规则与字符串型规则的区别:在
'count|1-100': 1中,初始值为数字1时,生成的最终结果是 1 到 100 的数值;如果在初始值中传入字符串'count|1-10': '★',则表示将该字符串重复 1 到 10 次。 - 动态数据调试验证:在联调前,建议对模板进行多次独立输出测试,验证极端情况下(例如数组只有最小值或达到最大值时)前端界面的排版和响应逻辑。
- 生产环境隔离:确保 Mock 拦截逻辑仅在开发或测试环境打包引入(通过
process.env.NODE_ENV === 'development'做条件判断引入),避免 Mock.js 拦截生产环境真实的 XMLHttpRequest 或 Fetch 请求。
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38








