前端mock数据的四种方式

4,735 阅读3分钟

在项目开发的过程中,前端与后端的工作往往是并行开始,作为前端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 --save

2. 新建 _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.js

4. 运行代码,可以看到network请求记录


方式4: ng-alain - @delon/mock + mockjs (推荐)

如果你的项目是使用ng-alain脚手架初始化的, ng-alain提供@delon-mock库来实现mock数据,并且是无侵入式的,相当于帮你做了场景3的工作,并且用法也很简单。

优点: 

  1. 开发无侵入
  2. 用法简单
缺点: 

  1.  对于没有用到ng-alain脚手架的项目,没办法使用

1. 在_mock文件夹下创建自己要mock文件(记得在index.ts里export)


2. 导入到DelonModule


3. 导入到AppModule




参考链接:

正确开启Mockjs的三种姿势:入门参考(一)

Mock.js

ng-alain @delon-mock