vue-cli项目中使用Mockjs详解


Posted in Javascript onMay 14, 2018

背景

前端在早期jQuery时代时,前端功能和后端工程基本上都是合在一起,典型的就是常见的maven工程下面的webapp目录包含前端各类静态资源文件。

这个时候,我们总是会遇到这些问题:

  1. 老大,接口文档还没输出,我的好多活干不下去啊!
  2. 后端小哥,接口写好了没,我要测试啊!
  3. 测试时间不够啊,就要发版了,今天难道我有看明天的太阳升起?

诸如种种,就是一句话:劳资,再也不要指望你们了!

node出现之后,准确的说是前后端分离之后,前端迫切需要一种机制,不在需要依赖后端接口开发。经过这几年的发展,有好多大牛在这方面进行了研究。

现在我们终于可以实现真实模拟测试啦。如今天的主角 mockjs

使用详解

1.首先在 src 目录创建 mock 文件夹,定义 mock 主文件 index.js ,在该文件中定义拦截路由配置;

/**
 * 定义本地测试接口,最好与正式接口一致,避免联调阶段修改工作量
 */
// 引入mockjs
import Mock from 'mockjs';
// 引入模板函数类
import record from './presc-record-api';

Mock.setup({
 timeout: 800, // 设置延迟响应,模拟向后端请求数据
});

// Mock.mock( url, post/get , 返回的数据);
Mock.mock(/\/api\/healthPlat\/getRecipe\/\w*\/\w*/, 'get', record.getRecipe);

2.在指定的文件中定义模板函数类,示例:

// 获取 mock.Random 对象
// 引入mockjs
import { Random } from 'mockjs';
import Utils from './Utils';

function getRecipe(req) {
 // mock一组数据
 const data = [];
 for (let i = 0; i < 10; i += 1) {
  const o = {
   recipeId: Random.guid(),
   billId: Random.string(10),
   orgId: Random.string('number', 8, 10),
   viewName: Random.cword(4, 16), // 随机生成任意名称
   personName: Random.cname(),
   reason: Random.csentence(10, 32),
  };
  data.push(o);
 }
 // 返回响应数据对象
 return Utils.setRes(req, {
  data: {
   idCard: Random.id(), // 随机
   details: data,
  },
  totalCount: 20,
 });
}

export default {
 getRecipe,
};

3.在 main.js 中引入 mock/index.js 文件;

// 引入mock文件
import './mock/index'; // mock 方式,正式发布时,注释掉该处即可

接下来的工作就是配置你的 mock 路由以及模板函数啦。Have Fun!

踩的坑

这里我介绍一下在 vue-cli 中使用 Mockjs 踩到的坑:

1.请求路径包含变量,我该怎么办?

使用过 router 码友知道,我们经常要处理地址中包含参数的路由,此时我们只需要在 Mockjs 中使用正则表达式去匹配路径即可完成,示例:

Mock.mock(/\/api\/healthPlat\/getRecipeDetail\/\w*\/\w*/, 'get', record.getRecipeDetail);

即我们只在变量的地方使用正则字符集合去匹配我们的变量。

2.为什么在控制台里面的 network 中没有看到我的请求?

刚开始测试时,我查看 network 没有看到请求,感到很奇怪!就自问自己几个问题:

  1. 为什么在 main.js 入口文件中引入 mockjs 的相关配置文件?
  2. 入口文件不都是在 webpack 中被编译,然后在浏览器中执行的吗?
  3. 控制台没有拦截到请求,那就是没有拦截到发送到服务器的请求了,对吧?

带着这些问题,阅读源码和文档,发现:

  1. 源码中首先查找是否在 Mockjs 中定义了该请求,有则进行拦截,然后使用其模拟请求对象 MockXMLHttpRequest 进行响应,即此时不发送 XHR 请求;
  2. 否则使用本地标准 XHR 对象进行请求,此时可以在控制台 network 中看到请求信息

因此,在 main.js 入口文件中引入 mockjs 的相关配置文件,即是在前端代码中加入了 Mockjs 的模拟方式,它将在浏览器中被执行,而不是真正的发送请求,不过我们可以将其打印到控制台进行查看。

网友评论可以在服务器中使用 mockjs ,此时就是真是的请求,可以在控制台中查看到请求信息,此处本人未进行相应实践,有兴趣的可以参看mock-server:

3.使用模板语法,返回的数据里面包含规则“|rules”,导致解析或取值失败,我该怎么办?

刚开始的时候,我按照文档上说的模板语法进行配置,如:

vue-cli项目中使用Mockjs详解

看到属性 code 居然带着规则一起返回了,我说我请求为啥没有解析成功啊,原来 res.code 一直是 undefined ,这是坑啊。
查看源码和可以搜到的网上示例发现:没有使用模板规则的现象,而是使用 mockjs 提供的内置函数来实现,如 .id() .cname() 等等方法。

于是我将mock相关文件中 code 定义改成下面这样:

function setRes(req, options) {
 window.console.log(req.url);
 const { code = Random.int(0, 5) >= 1 ? 1 : 0, message, data = {}, totalCount = 100 } = options;
 const result = {
  code,
  message: message || ['失败', '错误', '异常'][Random.integer(0, 2)],
  data,
  totalCount,
 };
 window.console.log(result);
 return result;
}

刚开始的时候属性code是这样定义的—— 'code|1', true, ,后来改成了 code = Random.boolean(),发现生成 false 的概览太高了,不适合我们真实的场景。

想到我们只需要增加 code 为 1 的概率,于是本人使用 Random.int(0, 5) 随机生成一个整数,当这个整数大于等于1,我们将 code 设置为 1 ,其他情况为 0 。

也就是说从概率上将,成功的概率为 0.8,失败的概率为 0.2,基本符合我们测试要求,哈哈,机智不^<^。

4.模拟异步请求的过程,发现请求好像是瞬间完成,loading效果没生效

刚开始的时候,没有设置延迟响应,每次请求都好像是瞬间完成的,没有一步操作的那种等待感,没有看到loading罩层出现。
自己debug时,loading罩层是有的,于是想到:请求没有被延迟,而是被同步执行了。

想到lodash.debounce 函数有延迟网络请求、稀释事件、延迟执行的效果,于是将模板函数用 debounce 包裹起来,如下:

Mock.mock('/api/healthPlat/chronicdisease', 'get', debounce(record.chronicdisease, 600));

结果出现有意思的事情:当请求比较频繁,在延迟时间内,本次请求得到的响应数据是上次请求的结果。这显然不是我们希望看到的,而且我们一般是用 debounce 的来稀释请求的,用在请求发送之后显然违背了我们的初衷。

翻阅 mockjs 文档,发现作者已经考虑了这个事情。哎,辛苦忙活了大半天,还是要好好看文档啊。具体如下:

Mock.setup({
 timeout: 800, // 设置延迟响应,模拟向后端请求数据
});

5. Mock 无法拦截带参数的 get 请求

刚开始时,发现设置的有些 get 请求总是请求不到 mock 的数据,而有些 get 请求能得到 mock 的数据,post 则不存在这样的问题。非常郁闷!

仔细 debug 时发现:get 请求带参数时失败,找不到路径;get 请求不带参数成功,路径没找到,获取到 mock 的数据;post 路径正确找到,成功得到 mock 数据。

这时突然意思到:get 请求的路径默认后面会加上参数,因此和设置的路径没有匹配上,导致路径没找到,请求失败。
于是本人将路径改成正则表达式,就好了。如:

// 刚开始字符串路径,带参数的 get 请求匹配失败
Mock.mock('/api/healthPlat/renewCancel', 'get', manage.renewCancel);

改成下面这样就好了:

// 正则表达式路径,带参数的 get 请求匹配成功
Mock.mock(/\/api\/healthPlat\/renewCancel/, 'get', manage.renewCancel);

但是实际开发过程中,发现上述正则表达式不够完备,如后续我们又另一个路径 /api/healthPlat/renewCancelAddr 也会匹配上述地址,这不是我们希望有的。

此时我们只需改进下正则表达式即可:

// 正则表达式路径,带参数的 get 请求匹配成功
Mock.mock(/\/api\/healthPlat\/renewCancel(|\?\S*)$/, 'get', manage.renewCancel);

即只有路径为 /api/healthPlat/renewCancel 的 get 请求才会匹配上述规则。

最后建议:get 请求都用正则表达式书写路径;post 字符串和正则都行;

总结

mock虽然存在以上所涉及的局限和问题,不过对于日常自测联调还是很有益处,个人觉得主要还是简单可行。当然本文所述方式,不仅仅局限在 vue-cli 中,其他框架中亦可按此法进行配置。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript中With语句用法实例
May 14 Javascript
javascript对象的创建和访问
Mar 08 Javascript
由简入繁实现Jquery树状结构的方法(推荐)
Jun 10 Javascript
第三篇Bootstrap网格基础
Jun 21 Javascript
纯JavaScript 实现flappy bird小游戏实例代码
Sep 27 Javascript
jquery实现折叠菜单效果【推荐】
Mar 08 Javascript
JS手机端touch事件计算滑动距离的方法示例
Oct 26 Javascript
Vue中对比scoped css和css module的区别
May 17 Javascript
原生JS实现手动轮播图效果实例代码
Nov 22 Javascript
vue里如何主动销毁keep-alive缓存的组件
Mar 21 Javascript
vue内置组件component--通过is属性动态渲染组件操作
Jul 28 Javascript
vue中的计算属性和侦听属性
Nov 06 Javascript
vue使用自定义icon图标的方法
May 14 #Javascript
基于Vue2x的图片预览插件的示例代码
May 14 #Javascript
vue组件中的数据传递方法
May 14 #Javascript
vue如何在自定义组件中使用v-model
May 14 #Javascript
JavaScript常用数学函数用法示例
May 14 #Javascript
JavaScript中常见内置函数用法示例
May 14 #Javascript
纯js封装的ajax功能函数与用法示例
May 14 #Javascript
You might like
Notice: Trying to get property of non-object problem(PHP)解决办法
2012/03/11 PHP
gd库图片下载类实现下载网页所有图片的php代码
2012/08/20 PHP
php记录代码执行时间(实现代码)
2013/07/05 PHP
PHP采集类snoopy详细介绍(snoopy使用教程)
2014/06/19 PHP
PHP中变量引用与变量销毁机制分析
2014/11/15 PHP
使用PHP和JavaScript判断请求是否来自微信内浏览器
2015/08/18 PHP
javascript 对表格的行和列都能加亮显示
2008/12/26 Javascript
javawscript 三级菜单的实现原理
2009/07/01 Javascript
jQuery学习笔记之jQuery的事件
2010/12/22 Javascript
JQuery一种取同级值的方式(比如你在GridView中)
2012/03/15 Javascript
jQuery对象数据缓存Cache原理及jQuery.data方法区别介绍
2013/04/07 Javascript
计算新浪Weibo消息长度(还可以输入119字)
2013/07/02 Javascript
javascript的创建多行字符串的7种方法
2014/04/29 Javascript
简介JavaScript中Math.LOG10E属性的使用
2015/06/14 Javascript
纯JS实现本地图片预览的方法
2015/07/31 Javascript
关于javascript中dataset的问题小结
2015/11/16 Javascript
浅析$(function) ready和onload 的区别
2016/09/03 Javascript
jquery组件WebUploader文件上传用法详解
2020/10/23 Javascript
Angular2库初探
2017/03/01 Javascript
在JS中如何把毫秒转换成规定的日期时间格式实例
2017/05/11 Javascript
Vue2.0基于vue-cli+webpack父子组件通信(实例讲解)
2017/09/14 Javascript
Vue函数式组件的应用实例详解
2019/08/30 Javascript
js实现html滑动图片拼图验证
2020/06/24 Javascript
通过实例解析JavaScript常用排序算法
2020/09/02 Javascript
在vue中给后台接口传的值为数组的格式代码
2020/11/12 Javascript
[01:45]2014DOTA2 TI预选赛预选赛 大神专访第二弹!
2014/05/20 DOTA
Python循环语句之break与continue的用法
2015/10/14 Python
Python简单实现安全开关文件的两种方式
2016/09/19 Python
Python与Java间Socket通信实例代码
2017/03/06 Python
Python操作MongoDB详解及实例
2017/05/18 Python
python利用高阶函数实现剪枝函数
2018/03/20 Python
Python3中详解fabfile的编写
2018/06/24 Python
keras.layer.input()用法说明
2020/06/16 Python
机电一体化应届生求职信范文
2014/01/24 职场文书
银行办公室岗位职责
2014/03/10 职场文书
Java面试题冲刺第十九天--数据库(4)
2021/08/07 Java/Android