怎么使用 Mock.js 生成嵌套对象、数组及自定义随机数据

作者:闭包旅人

时间:2026-10-30

浏览:374

深入讲解如何使用 Mock.js 的数据模板语法(DTD)生成深层嵌套对象、指定长度或区间的动态数组,并通过 Mock.Random 扩展自定义业务格式的随机数据。

文章目录
怎么使用 Mock.js 生成嵌套对象、数组及自定义随机数据
图 0:Mock.js 数据生成管线示意图 —— 从模板定义到结构化 JSON 交付

在前后端分离的开发流程中,前端常因后端接口尚未就绪而无法推进联调。使用 Mock.js 可以通过声明“数据模板(Data Template Definition,简称 DTD)”和内置的“随机占位符(Mock.Random)”,完全脱离真实服务端,本地模拟出贴近真实业务的多层级嵌套对象、特定长度范围的数组以及符合业务规范的定制随机数据。

一、Mock.js 的核心语法机制与接入步骤

Mock.js 的核心思想是“在属性名中定义生成规则,在属性值中提供基础样本或占位符”。其标准声明格式遵循以下结构:

'name|rule': value

其中,name 是输出 JSON 中的目标键名;|rule 是生成规则,负责控制生成对象的子项数量、数组长度或数值范围;value 则是模版初值,可以包含具体的字面量、内嵌的子模板,或者是带 @ 前缀的随机数据占位符。

实现一套包含复杂对象、数组和自定义规则的数据模拟,通常遵循标准化的四步接入流程:

怎么使用 Mock.js 生成嵌套对象、数组及自定义随机数据
图 1:使用 Mock.js 构造与输出复杂数据的四步流程

二、生成层级嵌套对象

在复杂的管理后台或微服务接口中,响应通常由外层的通用包头和深层嵌套的领域数据组成。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 生成嵌套对象、数组及自定义随机数据
图 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 就会将其识别为占位符并调用对应的生成函数。

怎么使用 Mock.js 生成嵌套对象、数组及自定义随机数据
图 3:模板规则结构与 Random 扩展占位符计算机制

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 请求。
怎么使用 Mock.js 生成嵌套对象、数组及自定义随机数据
图 4:Mock.js 复杂数据构造、边界防护与工程落地实践总结

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章