MockJS介绍
mockjs是一款用于模拟随机数据、模拟ajax请求的工具,它的用法简单,模拟数据的种类丰富,一目了然,可用性强、易用性好。
可以让前端开发者可以独立于后端开发者来进行开发。
官网的文档不是很好用,可以使用我自己复刻的doc
下面快速门中的案例可以到我自己复刻的doc中玩一玩。点击标记中的区域或者打开控制台输入代码回车。
快速入门
先安装、再引入、之后调用Mockjs中的方法,它支持两种使用方式:数据模板定义、数据占位符定义。同时它也支持请求的拦截、数据和模板的校验等。
- 数据模板定义:用Mockjs中内置模板字符串规则来配合Mockjs的mock方法来生成数据,通常它们并不是那么好理解,得结合源码里的实现来理解。
- 数据占位符定义:直接使用Mockjs中的各种模板占位符和各种模拟数据的API方法来生成数据。
- 请求的拦截:源码中是劫持了原生的请求对象,然后中间做了一层代理,在这个代理层实现了Mock.js自己的请求对象,然后拦截url等,最后返回你自定义的结果。
import Mock from 'mockjs'
// 数据模板定义的方式
Mock.mock({
"star|3-5": "⭐",
"size|1-10": 10,
"isOk|1": true,
"object|2": {
"test1": '测试1',
"test2": '测试2',
"test3": '测试3',
},
"array|1": [
"one",
"two",
"three",
],
"who": "我",
"谁": function () {
return this.who;
},
"username": /[a-zA-Z]{1,}[0-9@_]/,
"password": /[a-zA-Z-0-9_]{6,18}/,
"path": {
name: 'test',
age: 18,
obj: {
name: 'fest',
age: 17,
boyfriend: '@/path/name',
boyfriendAge: '@../age'
}
}
})
// 数据占位符
// Basic 基础
/**
boolean
natural
integer
float
character
string
range
*/
// Date 时间
/**
date
time
datetime
now
*/
// Image 图片
/**
image
dataImage
*/
// Color 颜色
/**
color
hex
rgb
rgba
hsl
*/
// Text 文本
/**
paragraph
sentence
word
title
cparagraph
csentence
cword
ctitle
*/
// Name 姓名
/**
first
last
name
cfirst
clast
cname
*/
// Web 网站
/**
url
domain
protocol
tld
email
ip
*/
// Address 地址
/**
region
province
city
county
zip
*/
// Helper 帮助
/**
capitalize
upper
lower
pick
shuffle
*/
// Miscellaneous 混淆
/**
guid
id
increment
*/
// 请求的拦截
/**
第一步:先调用`Mock.setup`这个方法,这个方法中会去劫持原生的请求对象
第二步:调用`Mock.mock(url, ...)`这个方法,这个方法如果第一个参数不是一个对象,就会进行url拦截。
*/
Mock.setup({
timeout: 500,
// timeout: '500-800'
})
// Mock.mock( rurl, template )
// Mock.mock( rurl, function( options ) )
// Mock.mock( rurl, rtype, template )
// Mock.mock( rurl, rtype, function( options ) ),options中包含 url、type 和 body
mockjs是与window.XMLHttpRequest强相关的,如果你使用的浏览器的window.fetch,那mockjs不会去拦截的,你可以通过使用mockjs-fetch
,然后MockFetch(Mock) 一下,Mock就可以支持fetch的拦截。
mockjs拦截并自定义处理过后的请求,不会在浏览器开发工具中的NetWork中显示,因为那个请求没有真正发送出去。
解决的问题
- 前后端分离:让前端攻城师独立于后端进行开发。
- 增加
单元测试
的真实性:通过随机数据,模拟各种场景。 - 开发无侵入:不需要修改既有代码,就可以
拦截 Ajax
请求,返回模拟的响应数据。 - 用法
简单
:符合直觉的接口。 - 数据类型丰富:支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等。
- 方便扩展:支持支持扩展更多数据类型,支持自定义函数和正则。
使用习惯
一般都是纯前端的使用,mock数据呀,请求的拦截和响应的重写呀,这种使用方式非常的普遍。
当然也可以用作后端数据接口的使用,可以结合webpack-devServer来使用,比如在vue-cli中的devServer中的before中插入一个server-mock模块,在express中使用mockjs来模拟接口所需的数据,非常的nice。
纯前端的案例
这是一个纯前端增删改查的案例
import Mock from ’mockjs‘;
const GET = 'GET';
const POST = 'POST';
const DELETE = 'DELETE';
const PUT = 'PUT';
// ! 新增一个汽车
Mock.mock('/api/addCar', POST,function(config) {
console.dir(config);
const { carName, carNo, carImg } = config.data;
return Mock.mock({
code: 200,
msg: 'success',
data: {
carID: Mock.mock('@id()'),
carName,
carNo,
carImg
}
})
})
// !查看汽车列表
Mock.mock('/api/carList', GET,function(config) {
console.dir(config);
return Array(Mock.mock('@integer(50,100)')).fill(1).map(()=>{
return Mock.mock({
carID: Mock.mock('@id()'),
'carName|1': [
'奥迪4个圈',
'海神三叉戟',
'大牛向前冲',
'野马奔奔奔'
],
carName:
carNo: Mock.mock('@guid()'),
carImg: Mock.mock('@image("270x120", "#a0ffff", "#ffa0ff", "png", "车")'),
})
})
})
// ! 删除汽车
Mock.mock('/api/deleteCar/6',DELETE,function (config) {
console.dir(config);
// 当id为number时可以这么做
let result = /\/api\/deleteCar\/(\d+)/.exec(config.url)
let carID = Number(result[1])
return Mock.mock({
code: 200,
msg: carID + ' delete success!',
})
})
// !更新汽车
Mock.mock('/api/updateCar', PUT, function (config) {
console.dir(config);
const { carID, carName, carNo, carImg } = config.data;
return Mock.mock({
code: 200,
msg: 'success',
data: {
carID,
carName,
carNo,
carImg
}
})
})
TEST
浏览器的fetch API测试
// addCar
fetch('http://127.0.0.1:8080/api/addCar', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"carName": "红牛",
"carNo": "沪·61888",
"carImg": "xxxx"
})
})
.then(response => console.log(response));
// carList
fetch('http://127.0.0.1:8080/api/carList').then(response => console.log(response));
// deleteCar
fetch('http://127.0.0.1:8080/api/deleteCar/6', {
method: 'delete'
})
.then(response => console.log(response));
// updateCar
fetch('http://127.0.0.1:8080/api/addCar', {
method: 'put',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"carID": "6",
"carName": "红牛",
"carNo": "沪·61888",
"carImg": "xxxx"
})
})
.then(response => console.log(response));
REST Client 工具测试,RESTful API 风格的测试
### 测试新增汽车接口
POST http://127.0.0.1:8080/api/addCar HTTP/1.1
Content-Type: application/json
{
"carName": "红牛",
"carNo": "沪·61888",
"carImg": "xxxx"
}
### 测试查看汽车列表
GET http://127.0.0.1:8080/api/carList HTTP/1.1
Content-Type: application/json
{}
### 测试删除汽车
DELETE http://127.0.0.1:8080/api/deleteCar/6 HTTP/1.1
Content-Type: application/json
{}
### 测试更新汽车
DELETE http://127.0.0.1:8080/api/updateCar HTTP/1.1
Content-Type: application/json
{
"carID": "6",
"carName": "红牛",
"carNo": "沪·61888",
"carImg": "xxxx"
}
前后端结合的案例
开源项目地址:https://github.com/aiyoudiao/aiyou-server-mock
配置代码
'use strict'
const port = 19999
// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
// webpack-dev-server 相关配置
devServer: {
port: port,
open: true,
compress: true,
disableHostCheck: true,
overlay: {
warnings: false,
errors: true
},
before: require('./server-mock/server.js')
},
}
工程目录
原理剖析
先克隆一份mockjs的源码到本地,mockjs工程化相对来说比较老旧,是基于Grunt来进行构建的,不过代码风格挺不错。
源码的入口是./src/mock.js,里面的代码也比较的清晰,数据模板定义
的处理都放在mock.js中,而数据占位符定义
的处理
都放在同级目录下的random.js中。请求拦截
的处理都放在mockjax.js中,直接拦截XMLHttpRequest|ActiveXObject
,这部分代码在同级目录下的xhr.js中。
mokc.js的代码并不是很复杂,通过看这篇文章学会了它的使用后,可以下载它的源码进行阅读,都会用了,再去读源码就不会很难。