文章目录
什么是mock
在进行vue项目前后端分离的开发过程中,想必会遇到这样一个问题,前端已经设计好了页面,但是需要使用后端提供的接口来接收数据,但是往往后端还尚未设计好接口,并未给出完善的接口文档,此时我们前端又想要测试自己设计的是否符合需求,进行后续开发时,我们就需要用到mock。
mock.js是模拟一些产生一些虚拟的数据,并提供模拟的接口,可以让前端在后端接口还没有开发出来时进行独立开发,避免等待接口文档,降低效率。我们可以使用真实的url,mockjs可以拦截ajax请求,返回设定好的数据。
vue项目引入mock
实践是检验真理的唯一标准!接下来我们将要动手实操。
- 安装mock.js
npm install mockjs --save / yarn add mockjs --save
- 使用mock.js模拟数据和接口
// 新建一个mockApi.js模块 来保存我们模拟的接口。 在规范的vue项目中,在/src/api文件夹新建mockApi.js
var Mock = require('mockjs') // 导入mockjs
var arr2 = Mock.mock({
'list|22-100': [ // 生成一个 length是 22~100之间的数组list
{
'a': '@string(3,50)', // 生成3-50位的产品合同号-梯号
'b': '@string(3,50)', // 生成3-50位的保养合同号
'c': '@cname', // 生成客户名称
'd': '@string(3,50)', // 生成3-50位的现场客户梯号
'e': '@cname', // 生成巡视整改人员
'f': '@date(yyyy-MM-dd)' // 生成整改时间
}
]
})
// 获取列表数据的接口 第一个参数表示自定义的接口地址 第二个参数表示自定义的请求方法
// 第三个参数是回调函数,定义返回的数据
Mock.mock('http://www.bbb.com', 'get', () => {return arr2})
如下图:
下面是我自己模拟的数据及接口
var arr = []
arr = Mock.mock({
'list|22-100': [ // 生成一个 length是 22~100之间的数组
{ 'inspectionId': '@integer(3,1000000)', // 生成1-1000000之间的巡视工单id
'eleContractNo': '@string(3,50)', // 生成3-50位的产品合同号-梯号
'mntContractNo': '@string(3,50)', // 生成3-50位的保养合同号
'customerName': '@cname', // 生成客户名称
'onsiteEleName': '@string(3,50)', // 生成3-50位的现场客户梯号
'inspectionType|1': ['ELEVATOR', 'ESCALATOR'], // 生成作业类型
'userName': '@cname', // 生成保养巡视人员
'inspectionDate': '@date(yyyy-MM-dd)', // 生成巡视时间
'h|1': '@time(HH:mm)-@time(HH:mm)', // 生成巡视时间段
'orderCode|1': ['INITIATED', 'CHANGE_REQUEST', 'INSPECTION_AUDIT', 'COMPLETE'] // 生成订单状态
}
],
'code': '2000',
'message': '这是mock数据'
})
Mock.mock(RegExp('/inspection/work/order'), 'get', () => {return arr})
- 导入定义好的mockApi模块
//在main.js中导入定义好的mockApi模块
require('mockApi文件的地址')
如下图:
- 使用定义好的接口
// 方式一: 使用axios直接请求模拟接口
//在任意vue文件中 当然axios如果自己已经定义 请使用自己的 这里只做演示用
import axios from 'axios'
export default {
created() {
axios.get('http://www.bbb.com').then(res => {
// 这里的res就是mock模拟的接口返回的数据
})
}
}
// 方式二: 使用src/api中规范定义的接口
import request from '@/utils/request'
// 这是src/api文夹下tourOrderApiAndConfigs.js文件中定义的接口
export const api = {
// 分页显示巡视工单列表&&巡视工单查询接口
getTourOrderList: {
// 执行接口
doApi: (params) => {
return request({
url: 'inspection/work/order',
method: 'GET',
params: params
})
},
successTip: '执行成功', // 成功提示
failTip: '执行失败', // 失败提示
errorTip: '执行错误'// 错误提示
}
}
// 这是某个vue文件中调用接口的内容
import { api, pageConfig, exportConfig, searchConfig } from '@/api/tourOrderApiAndConfigs'
export default {
methods: {
getData() {
// 获取表格数据
const params = {
pageNum: this.pageNo,
pageSize: this.pageSize
}
api.getTourOrderList.doApi(params).then(res => {
console.log(res)
this.tableData = res.list.list
this.total = res.total
}).catch((err) => {
console.log(err)
})
}
}
}
具体用法及说明如图:
通过以上步骤,我们已经简单使用mock模拟生成一个获取表格数据的接口啦!效果图如下:
mock模拟数据生成列表并模拟实现已发起表单页面表格分页功能
接下来我将要模拟生成不同页面的数据列表,统一通过一个接口来实现。首先,我先描述一下我的业务需求:现在共有四个页面,分别为已发起表单、待修改表单、待审核表单和已完成表单页面。已发起表单查询的是所有数据,共分为两种状态:已完成和未完成。实际上模拟的数据是四种状态:
'orderCode|1': ['INITIATED', 'CHANGE_REQUEST', 'INSPECTION_AUDIT', 'COMPLETE'] // 生成表单状态
前端调用接口时会传入orderCode值返回不同状态的表单数据。首先,模拟一个数组存储数据(以下操作均在mockApi.js文件内进行)
// 模拟一个列表数据
var arr = []
arr = Mock.mock({
'list|22-100': [ // 生成一个 length是 22~100之间的数组
{ 'inspectionId': '@integer(3,1000000)', // 生成1-1000000之间的巡视工单id
'eleContractNo': '@string(3,50)', // 生成3-50位的产品合同号-梯号
'mntContractNo': '@string(3,50)', // 生成3-50位的保养合同号
'customerName': '@cname', // 生成客户名称
'onsiteEleName': '@string(3,50)', // 生成3-50位的现场客户梯号
'inspectionType|1': ['ELEVATOR', 'ESCALATOR'], // 生成作业类型
'userName': '@cname', // 生成保养巡视人员
'inspectionDate': '@date(yyyy-MM-dd)', // 生成巡视时间
'h|1': '@time(HH:mm)-@time(HH:mm)', // 生成巡视时间段
'orderCode|1': ['INITIATED', 'CHANGE_REQUEST', 'INSPECTION_AUDIT', 'COMPLETE'] // 生成订单状态
}
],
'code': '2000',
'message': '这是mock数据'
})
关于mock生成随机数据用法可以参考这篇作者文档Mock生成随机数据常用的类型规则
接下来我们需要模拟定义一个方法来处理前端传来的orderCode值来返回对应的数据
/**
* 模拟实现已发起巡视工单列表分页功能
* params: orderCode(N),pageNum(Y),pageSize(Y)
* returns: 数组+total(如startArr)
*/
var { ...finishArr } = arr // 对象深拷贝
const tourOrderListByOrdercode = function(options) {
var catchUrl = options.url
// 截取url中携带的参数
var querys = catchUrl.substring(catchUrl.indexOf('?') + 1).split('&')
var result = [] // 用来存储处理结果(存储请求参数--键值对)
for (var i = 0; i < querys.length; i++) {
var temp = querys[i].split('=')
if (temp.length < 2) {
result[temp[0]] = ''
} else {
result[temp[0]] = temp[1]
}
}
if (result.orderCode === 'CHANGE_REQUEST') { // 待修改表单orderCode状态
var { ...modifyArr } = arr // 对象深拷贝
modifyArr.list = modifyArr.list.filter(function(val) {
return val.orderCode === result.orderCode
})
return modifyArr
} else if (result.orderCode === 'INSPECTION_AUDIT') { // 待审核表单orderCode状态
var { ...passingArr } = arr
passingArr.list = passingArr.list.filter(function(val) {
return val.orderCode === result.orderCode
})
return passingArr
} else if (result.orderCode === 'COMPLETE') { // 已完成表单orderCode状态
finishArr.list = finishArr.list.filter(function(val) {
return val.orderCode === result.orderCode
})
return finishArr
} else { // 无参数orderCode,全查,对应已发起表单页面
var { ...startArr } = arr
const total = startArr.list.length
changePageAndSize(startArr) // 调用此方法实现分页功能
return {
list: startArr,
total: total,
code: '2000',
message: 'success'
}
}
// 根据参数pageNum与pageSize实现分页功能
function changePageAndSize(selfArr) {
var totalPage = []
var pageAllNum = Math.ceil(selfArr.list.length / result.pageSize) || 1
for (let i = 0; i < pageAllNum; i++) {
totalPage[i] = selfArr.list.slice(result.pageSize * i, result.pageSize * (i + 1))
}
selfArr.list = totalPage[result.pageNum - 1]
console.log(selfArr)
return selfArr
}
}
当模拟完成列表数据和处理数据的方法后,我们还需要模拟一个接口供前端调用,完成这一步,整个流程才算是结束了。具体如下:
Mock.mock(RegExp('/inspection/work/order' + '.*'), 'get', tourOrderListByOrdercode)
说明一下:RegExp('/inspection/work/order' + '.*')
这是正则表达式用法,此处具体含义是全匹配,无论/inspection/work/order'
后面携带的什么参数,携带了多少参数,此接口都能成功调用,这是mock模拟携带参数接口所需要使用的方法。
到这里,我们就已经实现了mock模拟数据生成列表并模拟实现已发起表单页面表格分页功能,并提供了前端调用的接口,前端只需要向后端传orderCode(非必须),pageNum(必须)和pageSize(必须)这三个参数并调用接口就能成功接收到模拟的数据,并实现分页功能啦!代码如下(相关说明已在前文指出):
// 这是src/api文夹下tourOrderApiAndConfigs.js文件中定义的接口
import request from '@/utils/request'
export const api = {
// 分页显示巡视工单列表&&巡视工单查询接口
getTourOrderList: {
// 执行接口
doApi: (params) => {
return request({
url: 'inspection/work/order',
method: 'GET',
params: params
})
},
successTip: '执行成功', // 成功提示
failTip: '执行失败', // 失败提示
errorTip: '执行错误'// 错误提示
}
}
// 这是某个vue文件中调用接口的内容
import { api } from '@/api/tourOrderApiAndConfigs'
export default {
methods: {
getData() {
// 获取表格数据
const params = { //向后端传参
orderCode: 'COMPLETE' // 此处需要传值时则赋予对应的状态值,不需要时,此代码不写
pageNum: this.pageNo,
pageSize: this.pageSize
}
api.getTourOrderList.doApi(params).then(res => {
console.log(res)
this.tableData = res.list.list
this.total = res.total
}).catch((err) => {
console.log(err)
})
}
}
}
mock实现数据的新增
那么,如何使用mock模拟实现数据的新增呢,首先,我们应该明确,模拟新增其实就是将新数据拼接到列表数组中。整个思路大致为:前端将新增数据通过调用接口传给"后端",然后"后端"将此数据拼接到之前的列表数组中("后端"指代mock)。步骤如下:
- 前端通过填写表单存储数据并调用接口传给"后端",截图及代码如下:
填写完表单后点击提交,调用新增接口。代码如下:
//这是src/api中tourOrderApiAndConfigs.js文件中定义的新增请求接口
import request from '@/utils/request'
export const api = {
// 表单新建接口
creatTourOrder: {
// 执行接口
doApi: (data) => {
return request({
url: 'inspection/create/order',
method: 'POST',
data: { obj: data }
})
},
successTip: '执行成功', // 成功提示
failTip: '执行失败', // 失败提示
errorTip: '执行错误'// 错误提示
}
}
// 这是新增页面提交按钮方法
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$confirm('确认提交表单吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 将时间段数组数据分别存入不同字段
this.ruleForm.beginInspectionPeriod = this.value1[0]
this.ruleForm.endInspectionPeriod = this.value1[1]
console.log(this.ruleForm)
if (this.ruleForm.inspectionType === '升降梯') {
this.ruleForm.inspectionType = 'ELEVATOR'
}
if (this.ruleForm.inspectionType === '扶梯') {
this.ruleForm.inspectionType = 'ESCALATOR'
}
console.log(this.ruleForm)
var obj = this.ruleForm
api.creatTourOrder.doApi(obj).then(res => { // 表单创建调用接口
console.log(res)
})
this.$router.push('startTourOrder')
this.$message({
type: 'success',
message: '工单新建成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
})
} else {
console.log('error submit!!')
return false
}
})
}
}
此时,前端已经将新增数据传给"后端",此时"后端"需要将这条新增数据拼接到原有列表数据中,以模拟实现新增功能。代码如下:
/**
* 数据的添加操作
* @param {*}
* @returns
*/
const listAdd = function(options) {
try {
var obj = JSON.parse(options.body).obj
obj.h = obj.beginInspectionPeriod + '-' + obj.endInspectionPeriod // 拼接成时间段
var newArr = []
newArr[0] = obj
arr.list = arr.list.concat(newArr[0]) // 将前台返回来的数据,拼接到数组中
return {
code: '2000',
message: '建单成功!'
}
} catch (error) {
return {
code: 'error',
message: '出现错误!'
}
}
}
Mock.mock('/inspection/create/order', 'post', listAdd)
到这里,我们就实现了使用mock完成数据的新增。结果如图:
mock实现数据列表的删除
删除其实和新增类似,删除需要前端传递一个参数id,"后端"根据这个id遍历数组并将其删除,返回新的数组,实现删除功能。当然,这个参数可以是个id集合,将这个集合传给"后端"实现删除(后文有实例说明)。
首先,前端调用请求接口并携带参数id。代码如下:
// 这桑src/api文件夹中tourOrderApiAndConfigs.js文件中定义的删除接口
import request from '@/utils/request'
export const api = {
// 巡视工单撤销与删除接口
tourOrderDelete: {
// 执行接口
doApi: (data) => {
return request({
// url: '/inspection/revoke/${info.eleContractNo}',
url: '/inspection/revoke',
method: 'POST',
data: { id: data }
})
},
successTip: '执行成功', // 成功提示
failTip: '执行失败', // 失败提示
errorTip: '执行错误'// 错误提示
}
}
// 这是已发起表单中的删除方法
methods: {
deleteKpi(index, row) {
// console.log(index)
this.$confirm('是否确认删除该巡视工单?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
var id = row.eleContractNo
api.tourOrderDelete.doApi(id).then(res => {
this.tableData = res.list
this.getData()
})
}).then(() => {
this.$message({
type: 'success',
message: '删除成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
})
}
}
此时,"后端"接收参数id并处理数组,实现删除。代码如下:
/**
* 删除表单
* @param id
* @return arr
*/
const listDelete = function(options) {
try {
const id = JSON.parse(options.body).id
console.log(id)
arr.list = arr.list.filter(function(val) {
return val.eleContractNo !== id // 过滤掉前台传过来的id对应的相应数据,并重新返回
})
if (finishArr !== '' && finishArr !== null) { // 已完成巡视工单删除
finishArr.list = finishArr.list.filter(function(val) {
return val.eleContractNo !== id // 过滤掉前台传过来的id对应的相应数据,并重新返回
})
}
return {
code: '2000',
message: '删除成功!'
}
} catch (error) {
return {
code: 'error',
message: '删除失败!'
}
}
}
Mock.mock('/inspection/revoke', 'post', listDelete)
到这里,我们就使用mock模拟实现了删除功能。
列表数据批量处理(如审核通过)
刚刚在说明模拟删除时提到,前端可以传递一个id集合给"后端",“后端"再处理这个id集合实现批量删除,由于我当时的业务需求并没有批量删除,只有一个批量通过,其实效果都是一样的,都是传给后端一个id集合。所以在这里,我将使用mock模拟实现批量通过功能(全选/选择某几项),首先,展示一下前端页面效果图:
当我点击通过按钮后,调用相应的接口,并将选中的数据的id集合传给"后端”。代码如下:
// 这是src/api文件夹中tourOrderApiAndConfigs.js文件定义的通过接口
export const api = {
// 巡视工单审核通过接口
// auditType判断
tourOrderAudit: {
// 执行接口
doApi: (data) => {
return request({
url: 'inspection/audit',
method: 'POST',
data
})
},
successTip: '执行成功', // 成功提示
failTip: '执行失败', // 失败提示
errorTip: '执行错误'// 错误提示
}
}
// 这是待审核表单页面定义的参数及通过方法
data() {
return {
selectData: [],
selectCount: 0,
form: {
auditType: '',
funId: []
}
}
},
methods: {
select(selection) {
this.form.funId = []
for (var i = 0; i < selection.selection.length; i++) {
this.form.funId.push(selection.selection[i].inspectionId)
}
},
selectChange(data) { // 全选/全不选
// 勾选
this.selectData = data
this.selectCount = data.length
this.form.funId = []
for (var i = 0; i < this.selectCount; i++) {
this.form.funId.push(data[i].inspectionId)
}
},
accessPass() {
if (this.selectCount === 0) {
this.$message({
type: 'warning',
message: '您并未选择工单,请先选择工单再进行操作'
})
} else {
this.$confirm('是否确认通过选中巡视工单?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.form.auditType = 1 // auditType是判断业务是通过还是需整改,1为通过
api.tourOrderAudit.doApi(this.form).then(res => {
console.log(res)
this.getData()
})
}).then(() => {
this.$message({
type: 'success',
message: '通过成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
})
}
},
}
此时,"后端"接收到前端传来的id集合–funId,进行处理后返回新数据。代码如下:
/**
*巡视工单需整改提交整改信息模拟接口(尚未完成)与巡视工单审核通过接口(已完成--正常)
* @param {*} options
* @returns
* 逻辑仍需处理,该模拟接口尚未完善
*/
const rectifyDataInput = function(options) {
try {
console.log(options)
const id = JSON.parse(options.body).auditType
const idList = JSON.parse(options.body).funId // 当审核通过时,这里的funId是一个inspectionId集合;需整改时,仅一个数据
var handleData = []
for (var i = 0; i < idList.length; i++) {
arr.list = arr.list.filter(function(val) {
if (val.inspectionId === idList[i]) {
val.orderCode = 'COMPLETE'
handleData.push(val)
}
return val.inspectionId !== idList[i] // 过滤掉前台传过来的id对应的相应数据,并重新返回
})
}
if (id === 1) { // 巡视工单审核通过
var newArr = []
newArr = handleData
finishArr.list = finishArr.list.concat(newArr) // 将该数据,拼接到已完成表单数组中
return {
list: finishArr,
code: '2000',
message: '巡视工单审核已通过!'
}
}
if (id === 0) { // 巡视工单需整改
console.log('还需整改!')
return {
code: '2000',
message: '整改信息提交成功!'
}
}
} catch (error) {
return {
code: 'error',
message: '整改信息提交失败!'
}
}
}
Mock.mock('/inspection/audit', 'post', rectifyDataInput)
到这里,我们就已经完成了批量通过功能。结果如下:
总结与心得
mock使用步骤
- 安装mock.js
- 使用mockjs模拟数据并开发接口
- 导入定义好的mockApi模块
- 使用定义好的接口
心得
通过使用mock来模拟数据和接口,能够很方便的为我们前端开发提供便利,我们不再必须先等后端设计完成接口后再进行开发了,非常实用!但是有一个地方需要说明一下,一般情况下我们只需要模拟出虚拟数据就够了,不需要继续模拟实现复杂的业务逻辑,比如新增、按状态查询等等,我们只需要按照后端提前给出的接口文档将需要传递的参数及字段规范好即可。当然,如果时间充裕的话,做一些上述的业务逻辑处理也是非常有意义的😁
关于mock的学习分享就到这里啦,如果内容中有不准确或者可以优化的地方欢迎各位大佬指出!