我们前后端分离框架中需要用到mock数据的地方,主要就是API,因此其他使用场景(如硬件mock、第三方系统API)本文不做示例介绍,因为其mock思路其实是一样的。
1、全局mock开关
API的mock数据主要分为两种,一种是零散的、手工发起的ajax API请求;另一种是被封装到控件内部的ajax API请求。不管是哪一种mock,首先我们在每个页面都会加载的core.js里面定义了一个全局的mock开关:mvcApp.mock = true/false,然后在页面加载完成后,判断如果设置mock==true,则提示用户/开发者当前使用的是mock数据!
为什么要设置这样一个全局的mock开关呢?主要基于以下两点考虑:
(1)设置全局的mock开关之后就不再需要针对每一个页面设置mock开关,更容易维护,避免项目中有多个mock开关而难以统一开关状态;
(2)如果发布时忘记将mock开关给关掉,那么发布之后一运行发布者就会发现mock开关忘了关,然后可以快速修复之后再重新发布,从而避免不小心将正式服更新为mock数据源。
正是由于以上两点考虑,我们的全局mock开关可以帮助程序开发者和发布者更不容易犯错。
下面笔者将会给大家展现全局的mock开关如何跟页面API配合,从而完成整个站点的mock状态控制。
2、普通API的mock
在我们的前端框架中,我们使用了grunt来将整个页面的全部JS文件打包成一个JS文件,因此,在我们的前端框架中,每个页面对应一个JS源文件的文件夹,在打包的时候,grunt会将该文件夹中的全部JS文件合并打包(发布到生产环境时将执行压缩混淆)。下图所展示的是我们admin端的一个列表页面所对应的的JS源文件目录(index文件夹):
可以看到该文件夹下面的第一个JS文件叫01.page.js,这个JS是整个页面的入口,包括定义了页面全部的配置(比如用到的ajax URL)。第2个文件是02.api.js文件,该文件包含了所有的ajax请求。我们把全部的ajax请求封装到这个文件中,也是为了更好的mock。
下面就让我们来看这个02.api.js大概长什么样子吧:
从上面的代码中可以看到,我们定义了page.api这个对象两次,而中间有一个if判断,那就是判断我们全局的mock开关是否处于开启中,如果mock开启,则不会执行return而会继续第二段page.api对象赋值的代码,这样第一段代码定义的page.api对象就被覆盖了,于是这个页面中的其他JS文件就将使用mock的数据。如果全局的mock开关处于关闭状态,那么第一段page.api对象赋值代码执行完成之后,就会调用if下面的return语句了,这样就不会执行第二段page.api对象赋值,于是这个页面的其他JS文件就将使用真实数据。
这就是全局mock开关在页面中的应用,使用方法简单而灵活。这样,前端开发人员就可以在API开发出来之前通过mock的API完成样式和交互。
3、以Grid控件为例的控件级mock
在WEB前端开发过程中,一定会用到大量的控件(UI组件)。如果这个控件(比如Grid)内部封装了ajax请求,那么其ajax的mock操作就很难通过上一小节中的mock方法实现。
下面,笔者就将以我们项目的Grid控件为例,给大家详细阐述我们的改造过程。
由于我们项目中的Grid控件是我们自己开发的,虽然只有300行代码,但是功能很强大,可定制性很高。因此,要改造我们的Grid就变得很容易了。
首先,我们定义了一个VueGrid类继承自Grid类,然后重写了其loadData这个ajax方法,请看下图:
改造之后的VueGrid类多了一个getMockDataFunction这个属性,在loadData方法中,首先判断该grid实例是否设置了getMockDataFunction属性,如果设置了再判断getMockDataFunction方法的返回值是否为空,如果返回值为空则也使用真实数据,因此使用mock数据的条件是很苛刻的:必须设置getMockDataFunction属性并且其返回值不能为null。
然后我们在VueGrid类中还公开了一个设置getMockDataFunction属性的方法,如下图: