玩转Mock.js:构建模拟数据的利器
Mock.js基础介绍
为什么需要Mock.js
- 对于前后端分离的项目,后端工程师的API数据迟迟没有上线;而前端工程师却没有JSON 数据进行数据填充,自己写后端模拟又太繁重;这个时候,Mock.js 就能解决这个问题,让前端工程师更加独立做自己
- 前后端分离:让前端攻城师独立于后端进行开发
- 开发无侵入:不需要修改既有代码,就可以拦截Ajax请求,返回模拟的响应数据
- 数据类型丰富:支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等
- 增加单元测试的真实性:通过随机数据,模拟各种场显
- 用法简单:符合直觉的接口
- 方便扩展:支持支持扩展更多数据类型,支持自定义函数和正则
 
- 原理:通过拦截XMLHttpRequest或fetch等网络请求,根据定义的规则返回模拟的数据。当开发者发起一个请求时,Mock.js会检查匹配的规则,并返回相应的模拟数据。
- 官方网站为:Mock.js (mockjs.com)
安装与测试
- Node下运行:创建Mock目录,npm instal mockjs;创建JS文件,键入官网示例代码运行即可输出对应的JSON格式的数据:
            
            
              js
              
              
            
          
          // 使用 Mock
var Mock = require('mockjs')
var data = Mock.mock({
    // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
    'list|1-10': [{
        // 属性 id 是一个自增数,起始值为 1,每次增 1
        'id|+1': 1
    }]
})
// 输出结果 将JavaScript对象转换为格式化的JSON字符串,并在控制台输出,null表示不使用自定义替换函数,4表示缩进为4个空格
console.log(JSON.stringify(data, null, 4))- 浏览器运行:直接在HTML文件中引入,编写代码在浏览器打开查看控制台输出:
            
            
              html
              
              
            
          
          <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="http://mockjs.com/dist/mock.js"></script>
    <script>
        const data = Mock.mock({
            'list|1-10': [{
                'id|+1': 1
            }]
        });
        console.log(data);
        console.log(JSON.stringify(data, null, 4));
    </script>
</body>
</html>Mock.js语法规范
- Mock.js的语法规范包括两个部分:数据模板定义规范(DTD)和数据占位符定义规范(DPD);
- 数据模板定义的规范包含3个部分:属性名、生成规则和属性值
            
            
              json
              
              
            
          
          '属性名|生成规则' : 属性值 //'name|rule' : value- 其中,字符串、数值有7种生成规则:
| 生成规则 | 说明 | 示例 | 
|---|---|---|
| min-max | 生成min~max之间的字符串 | 'list|1-10' | 
| count | 生成count个字符串 | 'list|5' | 
| min-max.dmin-dmax | 生成min~ max之间的浮点数,小数点位数在dmin ~dmax之间 | 'id|1-10.1-3':1 | 
| count.dcount | 生成count个字符串,小数点位数为dcount | 'id|8.2':1 | 
| min-max.dcount | //同上 | |
| count.dmin-dmax | //同上 | |
| +step | 每次进行累加一个值 | 'id|+1':1 | 
- 除了以上几种规则格式,还有布尔值、对象和数组等规则
| 生成规则 | 说明 | 示例 | 
|---|---|---|
| 布尔值 | 生成布尔值,1/2概率true | 'flag|1':true | 
| 布尔值min-max | 生成布尔值,概率为min/(min+max) | 'flag|1-10':true | 
| 对象count | 从对象中随机抽取count个属性 | 'obj|2':obj | 
| 对象min-max | 从对象中随机抽取min-max属性 | 'obj|1-3':obj | 
| 数组1 | 获取1次数组 | 'arr|1':arr | 
| 数组count | 重复count次组成新数组 | 'arr|2':arr | 
| 数组+1 | 累加 | 'arr|+1':arr | 
| 数组min-max | 重复min-max次组成新数组 | 'arr|1-2':arr | 
- 支持函数和正则表达式
| 生成规则 | 说明 | 示例 | 
|---|---|---|
| 函数 | 支持函数 | 'fn|1':function | 
| 正则 | 支持正则 | 'reg|1'😕[a-z]/ | 
- 数据定义的占位符@,占领属性值的位置
- 有两种方式可以输出这种随机占位符:
            
            
              js
              
              
            
          
          console.log(Mock.Random.cname());
console.log(Mock.mock('@cname'));- 所有占位符:
| Type | Method | 
|---|---|
| Basic | boolean,natural,integer,float,character,string,range,date,time,datetime,now | 
| Image | image,dataImage | 
| Color | color | 
| Text | paragraph,sentence,word,title,cparagraph,csentence,cword,ctitle | 
| Name | first,last,name,cfirst,clast,cname | 
| Web | url,domain,email,ip,tld | 
| Address | area,region | 
| Helper | capitalize,upper,lower,pick,shuffle | 
| Miscellaneous | guid,id | 
            
            
              js
              
              
            
          
          //随机中文人名,不带c就是英文
console.log(Mock.mock('@cname'));
//随机ID
console.log(Mock.mock('@id'));
//随机中文标题,不带c就是英文
console.log(Mock.mock('@ctitle'));
//随机ip地址
console.log(Mock.mock('@ip'));
//随机图片地址
console.log(Mock.mock('@image'));
//随机url地址
console.log(Mock.mock('@url'));
//随机颜色,十六进制
console.log(Mock.mock('@color'));
//随机数值
console.log(Mock.mock('@integer'));
//随机日期
console.log(Mock.mock('@datetime'));
//随机字符串
console.log(Mock.mock('@string'));- 如果没有想要的数据格式进行填充,可以使用扩展功能自己扩展:
            
            
              js
              
              
            
          
          //自行扩展占位符
Mock.Random.extend({
    cstore() {
        return this.pick([
            '宠物店',
            '美容店',
            '小吃店',
            '数码店',
            '快餐店'
        ]);
    }
});
console.log(Mock.mock('@cstore'));Axios快速实践
- axios.js是一个基于promise的HTTP库,支持浏览器·和Node环境;可以使用这个库来执行Ajax请求,获取JSON数据;可以利用axios发送get、post等一系列请求,然后得到数据
- 安装:
- node下运行:npm insatll axios
- 在浏览器使用:< script src="https://unpkg.com/axios/dist/axios.min.js">< /script>
 
- node下运行:
- 简单的在Node环境下实现远程获取json数据:
            
            
              js
              
              
            
          
          const axios = require('axios');
axios.get('url')
     .then(res => {
          console.log(res.data);
     })
     .catch(err => {
          console.log('错误' + err);
     });- 有时候需要在url地址配置参数进行数据筛选:
            
            
              js
              
              
            
          
          axios({
    method : 'get',
    url : 'url',
    params : {
        id : 1,
        status : 5
    }
}).then(res => {
    console.log(res.data);
});- 如果项目中产生多个异步请求,会根据耗时长短来执行;如果需要请求按指定的顺序执行,使用all()方法:
            
            
              js
              
              
            
          
          axios.all([
    axios({
        url : 'url',
        data : '1.异步'
    }),
    axios({
        url : 'url',
        data : '2.异步'
    }),
    axios({
        url : 'url',
        data : '3.异步'
    }),
]).then(axios.spread((res1, res2, res3) => {
    console.log(res1.config.data);
    console.log(res2.config.data);
    console.log(res3.config.data);
}));- 实例化操作与拦截操作:
            
            
              js
              
              
            
          
          const myAxios = axios.create();
myAxios.defaults.baseURL = 'url';
//请求拦截
myAxios.interceptors.request.use(config => {
    //打印,修改
    console.log('loading...');
    //config.url = '/data2.json';
    //config.timeout = 50;
    return config;
});
//响应拦截
myAxios.interceptors.response.use(response => {
    //修改返回数据的格式
    return response.data;
});
myAxios.request({
    method : 'get',
    url : '/data.json',
}).then(res => {
    console.log(res);
});Mock拦截axios请求
Mock.mock
- 假设axios异步请求的数据尚未上线或不全,然后通过mock请求拦截,随机生成填充的数据进行前端设计
            
            
              js
              
              
            
          
          //ajax
axios.request({
    method : 'get',
    url : 'url'
}).then(res => {
    console.log(res.data);
});
//mock拦截
Mock.mock('url', {
    'list|5-10' : [
        {
            'id|+1' : 1,
            'username' : '@cname',
            'email' : '@email',
            'gender' : '@boolean',
            'price' : '@integer'
        }
    ]
});Mock.setup
- 使用Mock拦截请求时,可以通过Mock.setup()配置进行特定的行为:
            
            
              js
              
              
            
          
          //响应时间为400毫秒(默认值是10-100)
Mock.setup({
    timeout: 400
})
// 响应时间介于200-600毫秒之间
Mock.setup({
    timeout: '200-600'
})- 注:目前,接口 Mock.setup( settings )仅用于配置 Ajax 请求,将来可能用于配置 Mock 的其他行为。
Mock.valid
- 校验真实数据 data是否与数据模板template匹配。
            
            
              js
              
              
            
          
          var template = {
    name: 'value1'
}
var data = {
    name: 'value2'
}
Mock.valid(template, data)
// =>
[
    {
        "path": [
            "data",
            "name"
        ],
        "type": "value",
        "actual": "value2",
        "expected": "value1",
        "action": "equal to",
        "message": "[VALUE] Expect ROOT.name'value is equal to value1, but is value2"
    }
]Mock.toJSONSchema
- 把 Mock.js 风格的数据模板 template转换成 JSON Schema。
            
            
              js
              
              
            
          
          const Mock = require('mockjs');
// 创建一个 Mock 对象
const mockData = Mock.mock({
    'list|1-10': [{
        'id|+1': 1,
        'name': '@cname',
        'age|18-60': 1
    }]
});
// 将 Mock 对象转换为 JSON Schema
const jsonSchema = Mock.toJSONSchema(mockData);
console.log(jsonSchema);Mock在Vue项目实践
- 创建好Vue项目,npm install mockjs安装mockjs包
- 新建.env.development,定义环境变量:
            
            
              md
              
              
            
          
          # 控制是否需要使用mock模拟的数据
MOCK = TRUE- 定义接口路由,在接口中并返回mock模拟的数据;在项目文件创建mock文件夹,定义index.js文件:
            
            
              js
              
              
            
          
          const Mock = require('mockjs')
module.exports = function (app) {
    if (process.env.MOCK == 'true') {
        // node中的express框架
        // 参数1: 接口地址;参数2:服务器处理函数
        app.use('/api/userinfo', (req, res) => {
            // 随机生成一个对象
            var data = Mock.mock({
                id: '@id',
                username: '@cname',
                date: '@date(yyyy-MM-dd)',
                description: '@paragraph',
                email: '@email',
                'age|18-40': 0
            })
            // 将模拟的数据转成json格式返回给浏览器
            res.json(data)
        })
    }
}- 在vue.config.js中配置devServer,在before属性中引入接口路由函数:
            
            
              js
              
              
            
          
          const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    // devServer在发送请求时,会先走到before指定的函数中进行处理,如果before中没有对应的接口路由,才会请求外网等
    onBeforeSetupMiddleware: require('./mock/index.js')
  }
})3.使用axios调用该接口,获取数据:
            
            
              vue
              
              
            
          
          <template>
  <div id="app">
    <h1>Test</h1>
  </div>
</template>
<script>
import axios from "axios";
export default {
  created() {
    axios.get('/api/userinfo').then(res => {
      console.log(res);
    })
  }
}
</script>
<style></style>总结与思维拓展
主流Mock方案对比
- 
代码侵入: - 直接在本地写死或者导入本地json数据文件
- 优点:简单快捷
- 缺点:冗余代码过多,需要一一剔除
 
- 
抓包工具: - 使用抓包工具对网络请求进行拦截,将其替换成我们需要的Mock数据
- 优点:真实性强
- 缺点:操作繁琐,成本较高
 
- 
本地服务: - 
使用express或者koa等框架编写后端接口 
- 
优点:真实,方便管理 
- 
缺点:前端 === 全栈 ? 
 
- 
- 
浏览器插件: - 运行与浏览器,避免了本地部署和使用第三发的服务
- 优点:方便快捷
- 缺点:?
- 注:这里笔者进行了一下实践,个人认为也是一种比较轻量级的快速上手方案,详情参考:一款好用的 Chrome Mock 插件 - 掘金 (juejin.cn)
 
- 
平台类: - 使用软件或者网页来进行接口管理模拟数据
- 优点:全面快捷
- 缺点:依赖后端,需要(maybe)收费
 
- 
请求拦截: - 通过拦截 XMLHttpRequest 或 fetch 等网络请求,然后根据自定义规则返回 mock 数据
- 优点:不在依赖后端,直接拦截请求,数据真实
- 缺点:一定的学习成本?