在项目开发的过程中,前端与后端的工作往往是并行开始,作为前端coding的我们,往往会先在前端mock数据,等到后端接口完成后再使用真实数据进行对接,但如果你要mock的数据有成千上万条呢?本文将讨论如何使mock数据这项工作达到“工作量小+灵活性高+代码侵入性小“。
首先,祭出mock数据的神仙利器 - mockjs
mockjs
数据类型丰富
支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等。拦截 Ajax 请求
拦截 Ajax 请求,返回模拟的响应数据。安全又便捷
比如项目里有一个用于管理订单网络请求的OrderMgtService
下面以获取销售订单列表数据为例:
方式1:只是mock假数据,不需要拦截ajax请求
缺点:代码侵入程度高,切换数据获取方式的代价大。
首先安装mockjs
npm install mockjs --save在需要mock数据的文件里,导入mockjs
import { Injectable } from '@angular/core';import { SaleOrder, ProductionOrder } from '../entities/order-entities';import { of, Observable } from 'rxjs';import { HttpResponseHandler } from '@bf/modeling/common';
import { AuthService } from '@bf/ide';
import { HttpClient } from '@angular/common/http';
import { URL } from 'url';
const Mock = require('mockjs');
@Injectable()
export class OrderMgtService {
constructor(
private authService: AuthService,
private httpResponseHandler: HttpResponseHandler,
private httpClient: HttpClient
) { }
/**
* 获取销售订单列表
* @param pageIndex 第几页
* @param pageSize 一页多少条
* @returns 销售订单列表
*/
getSaleList(pageIndex: number, pageSize: number): Observable<any> {
const data = Mock.mock({
pageIndex: pageIndex,
pageSize: pageSize,
total: 100,
'data|10': [
{
'id|+1': 1,
'no|+2': 1111 + pageIndex*1000,
name: 'name' + '@integer(1,6)',
'type|1': ['type1', 'type2', 'type3'],
customer: 'customer' + '@integer(1,6)',
manager: 'manager' + '@integer(1,6)',
'planCount': '@integer(2,100)',
'actualCount|1': '@integer(2,100)',
'status|1': ['notStart', 'hasStart', 'finish'],
planStartDate: (new Date()),//'@date(yyyy/MM/dd)',
planEndDate: (new Date()),//'@date(yyyy/MM/dd)',
actualStartDate: (new Date()),//'@date(yyyy/MM/dd)',
actualEndDate: (new Date()),//'@date(yyyy/MM/dd)',
}
]
})
return of(data);
}
}列表内容:
方式2: 拦截请求(推荐)
优点:相对于场景1来说,在不使用mock数据时,移除成本小
1. 新建_mock.ts文件
const Mock = require('mockjs);
Mock.mock(/\/sale-list*/, function(params){
const url = new URL(params.url);
const urlParams = new URLSearchParams(params.url);
const pageIndex = Number(urlParams.get(pageIndex));
const pageSize = Number(urlParams.get(pageSize));
return Mock.mock(
{
code: 0,
pageIndex: pageIndex,
pageSize: pageSize,
total: 100,
'data|10': [
{
'id|+1': 1,
'no|+2': 1111 + pageIndex * 1000,
name: 'name' + '@integer(1,6)',
'type|1': ['type1', 'type2', 'type3'],
customer: 'customer' + '@integer(1,6)',
manager: 'manager' + '@integer(1,6)',
'planCount': '@integer(2,100)',
'actualCount|1': '@integer(2,100)',
'status|1': ['notStart', 'hasStart', 'finish'],
planStartDate: (new Date()),//'@date(yyyy/MM/dd)',
planEndDate: (new Date()),//'@date(yyyy/MM/dd)',
actualStartDate: (new Date()),//'@date(yyyy/MM/dd)',
actualEndDate: (new Date()),//'@date(yyyy/MM/dd)',
}
]
}
);
});2. OrderMgtService 导入_mock.ts
import { Injectable } from '@angular/core';
import { SaleOrder, ProductionOrder } from '../entities/order-entities';
import { of, Observable } from 'rxjs';
import { HttpResponseHandler } from '@bf/modeling/common';
import { AuthService } from '@bf/ide';
import { HttpClient } from '@angular/common/http';
import { URL } from 'url';
import '..mock/_mock';
@Injectable()
export class OrderMgtService {
constructor(
private authService: AuthService,
private httpResponseHandler: HttpResponseHandler,
private httpClient: HttpClient
) { }
/**
* 获取销售订单列表
* @param pageIndex 第几页
* @param pageSize 一页多少条
* @returns 销售订单列表
*/
getSaleList(pageIndex: number, pageSize: number): Observable<any> {
const requestUrl = `uaa/api/v2/order-entry/sale-list?pageIndex=${pageIndex}&pageSize=${pageSize}`;
return this.httpResponseHandler.request$(
"",
"",
this.httpClient.get(requestUrl));
}
}方式3 : 真正的拦截ajax请求
依靠express搭建本地node.js服务,代码无侵入,并且在浏览器的调试页面的network列表里可以看到请求记录
优点:开发无侵入
缺点:需要具备nodejs技能, 门槛略高
1. 安装express
npm install express --save2. 新建 _mock.js 文件
const express = require('express');
const app = express();
app.use(/.*\/sale-list*/, function(req, res){
const pageIndex = req.query.pageIndex;
const pageSize = req.query.pageSize;
res.json(Mock.mock(
{
code: 0,
pageIndex: pageIndex,
pageSize: pageSize,
total: 100,
'data|10': [
{
'id|+1': 1,
'no|+2': 1111 + pageIndex * 1000,
name: 'name' + '@integer(1,6)',
'type|1': ['type1', 'type2', 'type3'],
customer: 'customer' + '@integer(1,6)',
manager: 'manager' + '@integer(1,6)',
'planCount': '@integer(2,100)',
'actualCount|1': '@integer(2,100)',
'status|1': ['notStart', 'hasStart', 'finish'],
planStartDate: (new Date()),//'@date(yyyy/MM/dd)',
planEndDate: (new Date()),//'@date(yyyy/MM/dd)',
actualStartDate: (new Date()),//'@date(yyyy/MM/dd)',
actualEndDate: (new Date()),//'@date(yyyy/MM/dd)',
}
]
}
));
});
app.listen('20000', () => {
console.log('监听端口 20000');
});
2. 网络请求地方的代码不动
import { Injectable } from '@angular/core';
import { SaleOrder, ProductionOrder } from '../entities/order-entities';
import { of, Observable } from 'rxjs';
import { HttpResponseHandler } from '@bf/modeling/common';
import { AuthService } from '@bf/ide';
import { HttpClient } from '@angular/common/http';
import { URL } from 'url';
@Injectable()
export class OrderMgtService {
constructor(
private authService: AuthService,
private httpResponseHandler: HttpResponseHandler,
private httpClient: HttpClient
) { }
/**
* 获取销售订单列表
* @param pageIndex 第几页
* @param pageSize 一页多少条
* @returns 销售订单列表
*/
getSaleList(pageIndex: number, pageSize: number): Observable<any> {
const requestUrl = `uaa/api/v2/order-entry/sale-list?pageIndex=${pageIndex}&pageSize=${pageSize}`;
return this.httpResponseHandler.request$(
"",
"",
this.httpClient.get(requestUrl));
}
}
3. 运行node
node _mock.js4. 运行代码,可以看到network请求记录
方式4: ng-alain - @delon/mock + mockjs (推荐)
如果你的项目是使用ng-alain脚手架初始化的, ng-alain提供@delon-mock库来实现mock数据,并且是无侵入式的,相当于帮你做了场景3的工作,并且用法也很简单。
优点:
- 开发无侵入
- 用法简单
- 对于没有用到ng-alain脚手架的项目,没办法使用
1. 在_mock文件夹下创建自己要mock文件(记得在index.ts里export)
2. 导入到DelonModule
3. 导入到AppModule
参考链接: