玩转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 数据
- 优点:不在依赖后端,直接拦截请求,数据真实
- 缺点:一定的学习成本?