mockjs模拟数据


了解mockjs

实际开发中,前后端分离,前端需要后端的接口去完成页面的渲染,但是并不能等到后端成员写完接口再开始进行测试。大部分情况下,前后端需要同时进行开发。因此便需要mockjs生成随机数据 & 拦截 Ajax 请求来进行后端接口模拟。

(后面的例子会使用到Axios,axios 是一个基于 Promise 用于浏览器和 nodejs 的 HTTP 客户端,我们后续需要用来发送 http 请求)

使用文档

官网地址:http://mockjs.com/

github 地址:https://github.com/nuysoft/Mock

Vue的引入Mockjs - demo1

完整代码 git: mockjsDemo1

npm install mockjs
yarn add mockjs
//下面的例子要用axios
yarn add axios
  • 在src路径下创建mock.js文件

  • 在main.js引入mock.js文件

  require('./mock')
//或者
import './mock'// 这里不用写 ./mock.js
  • 在mock.js文件中写
  //引入mockjs
  const Mock = require('mockjs')
  // 获取 mock.Random 对象
  const Random = Mock.Random;
  //使用mockjs模拟数据
  Mock.mock('/api/data', (req, res) => {//当post或get请求到/api/data路由时Mock会拦截请求并返回上面的数据
      let list = [];
      for(let i = 0; i < 30; i++) {
          let listObject = {
              title: Random.csentence(5, 10),//随机生成一段中文文本。
              company: Random.csentence(5, 10),
              attention_degree: Random.integer(100, 9999),//返回一个随机的整数。
              photo: Random.image('114x83', '#00405d', '#FFF', 'Mock.js')
          }
          list.push(listObject);
      }
      return {
          data: list
      }
  })

//上面也可以写成
Mock.mock('https://xxxxxxxxxx',{
    'list|5-10': [{// 直接5-10的程度生成
        'id|+1': 1,
        'username':'@cname',
        'email': '@email',
        'price': '@integer',
        'gender': '@boolean'
    }]
})
  • 在Vue中设置
      mounted:function() {
            axios.get('/api/data').then(res => {//get()中的参数要与mock.js文件中的Mock.mock()配置的路由保持一致
              this.data = res.data.data;
              console.log(res.data);//在console中看到数据
              this.tableData=res.data.data
            }).catch(res => {
              alert('wrong');
            })
          },  

上面的运行成功了~ 那么就可以开心的用mockjs了 ~~下面的只是更换所需的功能

Mock函数的解释

Mock.mock(rurl? rtype? template|function(options)) 生成模拟数据

  • rurl - 可选
    表示需要拦截的 URL,可以是 ‘字符串’ 或 ‘正则’。例如:

    'www.xxx.com/list.json'
    /\/www\.xxx\.com\/list\.json/
  • rtype - 可选
    表示需要拦截的 Ajax 请求方法。例如: GET、POST、PUT、DELETE 等

  • template - 可选
    表示数据模板,可以是 ‘对象’ 或 ‘字符串’。例如:{ ‘data|1-10’: [{}] } 或 ‘@EMAIL’

  • function(options) - 可选
    表示用于生成响应数据的函数。
    options 指向本次请求的 Ajax 选项集,包含: url type body 3 个属性

mockjs 数据生成语法

稍微看看吧, 不想看可以直接按照例子走就完事儿

mock.js 的语法规范包含 2 部分

1.数据模板定义规则(Data Template Definition, DTD)
2.数据占位符定义规则(Data Placeholder Definition, DPD)

DTD 规范

每个属性由 3 部分组成:属性名、生成规则、属性值。

‘name|rule’: value

  • name - 属性名
  • rule - 生成规则
  • value - 属性值

注意点

1.属性名和生成规则,之间有一个 ‘|’
2.生成规则是 ‘可选的’
3.生成规则有 ‘7’ 种格式:

  • 1>min-max
  • 2>count
  • 3>min-max.dmin-dmax
  • 4>min-max.dcount
  • 5>count.dmin-dmax
  • 6>count.dcount
  • 7>+step

4.生成规则的含义,依赖 ‘属性值类型’ 来确定(意思是:生成规则,根据属性值 ‘类型’ 的不同,会生成不同的模拟数据)
5.属性值中可以含有 ‘@占位符’
6.属性值,指定了最终值的 ‘初始值’ 和 ‘类型’

DPD 规范

占位符,只是在 ‘属性值’ 中占个位置,并不会出现在生成的属性值中。

  • @占位符
  • @占位符(参数[, 参数])

注意点

  • 1.用 ‘@’ 来标识其后的字符串为 ‘占位符’
  • 2.占位符引用的是 ‘Mock.Random’ 中的方法
  • 3.通过 Mock.Random.extend() 来 ‘自定义’ 占位符
  • 4.’占位符’ 也 ‘可以引用’ ‘数据模板’ 的属性
  • 5.’占位符’ 会 ‘优先’ 引用 ‘数据模板’ 的属性
  • 6.’占位符’ 支持 ‘相对路径’ 和 ‘绝对路径’

例子

注意下面的参数都是可选的哈

"base": {
    "range": "@range(3)",// [1,2,3]
    "range": "@range(3, 7)",// [3,4,5,6]
    "rangeWithGap": "@range(1, 10, 3)",//start-1,stop-10,step-3 [1,4,7]
    "string": "@string(7, 20)", //输出7-20个字符长度的字符串
     "string": "@string('lower', 5)",//Random.string(pool, length)或者(pool,min,max) pool:'lower/upper/number/symbol'
    "character": "@character('abcde')",//随机从abcde中选一个字母
    //Random.character('lower/upper/number/symbol') 
    "float": "@float(60, 100)",//60 到 100 的浮点数 Random.float(min, max, dmin, dmax) dmin- 小数部分单个位数最小值 dmax 小数部分单个位数最大
    "integer": "@integer(60, 100)",//60 到 100 的整数
    "natural": "@natural(60, 100)",//60 到 100 的自然数
    "boolean": "@boolean" //boolean 类型 true,false
  },
  <!--时间类型-->
  "date": {
    "date": "@date",//1982-07-20
    "time": "@time",// 11:21:39
    "datetime": "@datetime",// 1972-12-16 02:04:24
    "now": "@now" //当前时间 2018-07-17 18:19:29  Mock.Random.now() Ranndom.now(format)
      //Mock.Random.now('month') => Ranndom.now(unit) unit = year、month、week、day、hour、minute、second、week
  },
  <!--图片-->
  "image": {
    "image": "@image('200x100', '#50B347', '#FFF', 'EasyMock')" // https://dummyimage.com/200x100/50B347/FFF&text=EasyMock 尺寸 背景 文字颜色 提示信息
  },
  <!--颜色系列-->
  "color": {
    "color": "@color", //16进制颜色值#79e0f2
    "hex": "@hex", // #f2e179
    "rgb": "@rgb", //rgb(189, 121, 242)
    "rgba": "@rgba",//rgba(189, 121, 242, .7)
    "hsl": "@hsl" //hsl(136, 82, 71)
  },
  <!--文案类-->
  "text": {
    "paragraph": "@paragraph(1, 3)",// 随机段落
    "sentence": "@sentence(3, 5)",// 随机句子
    "word": "@word(3, 5)",// 随机3-5个字母
    "title": "@title(3, 5)",// 随机3-5个单词的title
    "cparagraph": "@cparagraph(1, 3)",
    "csentence": "@csentence(3, 5)",
    "cword": "@cword('零一二三四五六七八九十', 5, 7)",
    "ctitle": "@ctitle(3, 5)"
  },
  <!--姓名-->
  "name": {
    "first": "@first",//姓
    "last": "@last",//名
    "name": "@name",//姓名
    "cfirst": "@cfirst",
    "clast": "@clast",
    "cname": "@cname"
  },
  <!--网站-->
  "web": {
    "url": "@url",//url地址
    "domain": "@domain",//域名
    "protocol": "@protocol",//协议
    "tld": "@tld",
    "email": "@email",//邮箱
    "ip": "@ip"//ip地址
  },
  <!--地址-->
  "address": {
    "region": "@region",//区域
    "province": "@province",//省
    "city": "@city(true)",//市
    "county": "@county(true)",//区 带true则携带上级
    "zip": "@zip"
  },
  "helper": {
    "capitalize": "@capitalize('hello')",
    "upper": "@upper('hello')",//全大写单词
    "lower": "@lower('HELLO')",//全小写单词
    "pick": "@pick(['a', 'e', 'i', 'o', 'u'])", //随机选择一个字母
    "shuffle": "@shuffle(['a', 'e', 'i', 'o', 'u'])" //打乱数组顺序
  },
  "miscellaneous": {
    "id": "@id",//身份证id
    "guid": "@guid",//生成32位的随机id
    "increment": "@increment(1)"//自增数,阶度为1
  }

date format

日期的模板 其实这个很多地方也都通用 airbnb那个以及moment js 都是这个

format Description Example
yyyy A full numeric representation of a year, 4 digits 1999 or 2003
yy A two digit representation of a year 99 or 03
y A two digit representation of a year 99 or 03
MM Numeric representation of a month, with leading zeros 01 to 12
M Numeric representation of a month, without leading zeros 1 to 12
dd Day of the month, 2 digits with leading zeros 01 to 31
d Day of the month without leading zeros 1 to 31
HH 24-hour format of an hour with leading zeros 00 to 23
H 24-hour format of an hour without leading zeros 0 to 23
hh 12-hour format of an hour without leading zeros 1 to 12
h 12-hour format of an hour with leading zeros 01 to 12
mm Minutes, with leading zeros 00 to 59
m Minutes, without leading zeros 0 to 59
ss Seconds, with leading zeros 00 to 59
s Seconds, without leading zeros 0 to 59
SS Milliseconds, with leading zeros 000 to 999
S Milliseconds, without leading zeros 0 to 999
A Uppercase Ante meridiem and Post meridiem AM or PM
a Lowercase Ante meridiem and Post meridiem am or pm
T Milliseconds, since 1970-1-1 00:00:00 UTC 759883437303

数据生成助手

数据模板生成模板 - demo2

http://mockjs.com/examples.html

mockJs 的模拟get请求

//vue
<button @click="getGoodsList">获取商品列表</button>
 methods: {
    async getGoodsList() {
      const { data: res } = await this.$http.get('/api/goodslist')
      console.log(res)
    }
 }
//mockjs
Mock.mock('/api/goodslist', 'get', {
  status: 200,
  message: '获取商品列表成功!',
  'data|5-10': [
    {
      id: '@increment(1)', // 自增的Id值
      // 'id|+1': 0, // 这也是在模拟一个自增长的 Id 值
      name: '@cword(2, 8)', // 随机生成中文字符串
      price: '@natural(2, 10)', // 自然数
      count: '@natural(100, 999)',
      img: '@dataImage(78x78)', // 指定宽高图片
      'answer|1': ["是", "否"]
    }
  ]
})

mockJs 的模拟post请求

//vue
<button @click="addGoods">添加商品</button>
  methods: { 
    async addGoods() {
      const { data: res } = await this.$http.post('/api/addgoods', {
        name: '菠萝',
        price: 8,
        count: 550,
        img: '',
        "user|1-3": [{   // 随机生成1到3个数组元素
            'name': '@cname',  // 中文名称
            'id|+1': 88,    // 属性值自动加 1,初始值为88
            'age|18-28': 0,   // 18至28以内随机整数, 0只是用来确定类型
            'birthday': '@date("yyyy-MM-dd")',  // 日期 
        },
      }) 
      console.log(res)
    }
  }
//mockjs
Mock.mock('/api/addgoods', 'post', function(option) {
  // 这里的 option 是请求相关的参数
  console.log(option)

  //一般的默认的return
  // return{
  //   status:200,
  //   message:'商品添加成功'
  // }

  //这里如果你要使用mock返回信息的话 就需要这样
  return Mock.mock({
    status: 200,
    message: '@cword(2,5)'
  })
})

删加增减的功能练习

注意这里的设置会有不同这里的完整代码 github_demo2

上面的都属于基本的简单实用 ~~下面咋们看看封装版本

封装mock模板!! - admin-ui

(下面的例子 基本完成了mock的基本设置 axios的基本设置 然后还有做axios封装)

目的

为了统一可以统一管理和集中控制数据模拟接口,我们对 mock 模块进行了封装,可以方便的定制模拟接口的统一开关和个体开关

文件结构

|- mock 
 |--modules
   |--- index.js:模拟接口模块聚合文件
   |--- login.js:登录相关的接口模拟
   |--- user.js:用户相关的接口模拟
   |--- menu.js:菜单相关的接口模拟

代码内容都是admin-ui里面的!!!!

封装之前

//简单的搭建沟通
import Mock from 'mockjs'

//前面的link可以不写
Mock.mock('http://localhost:8080/login',{
    data:{
        'token':'123159753456789'
        //其他数据
    }
})

Mock.mock('http://localhost:8080/user',{
    'name':'@name',//随机生成名字
    'email':'@email',//随机生成
    'age|1-10':5
})

Mock.mock('http://localhost:8080/menu',{
    'id':'@increment',//随机生成名字
    'name':'@menu',//随机生成
    'order|10-20':12
}) 

封装开始!!index.js

import Mock from 'mockjs'
import * as login from './modules/login'
import * as user from './modules/user'
import * as menu from './modules/menu'

// 1. 开启/关闭[业务模块]拦截, 通过调用fnCreate方法[isOpen参数]设置.
// 2. 开启/关闭[业务模块中某个请求]拦截, 通过函数返回对象中的[isOpen属性]设置.
fnCreate(login, true)//现在就暂时只有三个部分
fnCreate(user, true)
fnCreate(menu, true)

/**
 * 创建mock模拟数据
 * @param {*} mod 模块
 * @param {*} isOpen 是否开启?
 */
function fnCreate (mod, isOpen = true) {
  if (isOpen) {
    for (var key in mod) {
      ((res) => {
        if (res.isOpen !== false) {
          Mock.mock(new RegExp(res.url), res.type, (opts) => {
            opts['data'] = opts.body ? JSON.parse(opts.body) : null
            delete opts.body
            console.log('\n')
            console.log('%cmock拦截, 请求: ', 'color:blue', opts)
            console.log('%cmock拦截, 响应: ', 'color:blue', res.data)
            return res.data
          })
        }
      })(mod[key]() || {})
    }
  }
}

login.js

关于练习里面的login练习, 只是利用了session storage,实际上可以利用Vuex。 这里详细在另一篇文章

// 登录接口
export function login () {
  return {
    // isOpen: false,
    url: 'http://localhost:8080/login',
    type: 'get',
    data: {
      'msg': 'success',
      'code': 0,
      'data': {
        'token': '4344323121398'
        // 其他数据
      }
    }
  }
}

user.js

// 获取用户信息
export function getUser () {
  return {
    // isOpen: false,
    url: 'http://localhost:8080/user',
    type: 'get',
    data: {
      'msg': 'success',
      'code': 0,
      'data': {
        'id': '@increment', 
        'name': '@name', // 随机生成姓名
        'email': '@email', // 随机生成姓名
        'age|10-20': 12
        // 其他数据
      }
    }
  }
}
// 获取菜单信息
export function getMenu () {
  return {
    // isOpen: false,
    url: 'http://localhost:8080/menu',
    type: 'get',
    data: {
      'msg': 'success',
      'code': 0,
      'data': {
        'id': '@increment', 
        'name': 'menu', // 随机生成姓名
        'order|10-20': 12
        // 其他数据
      }
    }
  }
}

修改引入

组件内
//之前是
import mock from '@/mock/mock.js';
//改为
import mock from '@/mock/index.js';

这是封装成功的效果

踩坑

在vue中使用axios做网络请求的时候,会遇到this不指向vue,而为undefined。

解决 this的指向问题,要么箭头函数,要么直接let that=this

//mockjsDemo2
updateItem(id){
        var that = this;
        this.$http.post('/updateItem',{
          params: {
            updateId:id
          }
        }).then(function(res){
          console.log("更新数据",res);
          that.list = res.data.data;
        }).catch((err) => {
          console.log(err)
        })
      } 

mockjs 与 import export的大坑!!!!!!!!!!!!

注意 这里跟定义const let 这些其实没有很大关系 主要是理解三者联系

一般来说,如果是只是想测试写出比较简单的测试, 实际上直接写json获取 或者说直接写api接口都可以了,不用写复杂的mock文件

需求:写一个mockjs,模拟一个数据库,生成一个固定的数据array,并且统一操作删加减查

问题: data.js export getter函数给api文件,但是api文件直接使用export的getter函数时候,获取的值是空的

因为你在做梦啊~ 让mockjs 生成一个对于全部所有页面固定数据的表,因为要确保每个页面call的时候都是同一个数据arr。那么我总得存起来,但是由于是用import export的做法。那么我每次页面call的时候,还是要确保数据是新init的 。但是这时候init数据就变化了 所以总结一句“你在想peach!!”

Reference

在vue-cli项目下简单使用mockjs模拟数据 (demo1)

掌握MockJS (demo2)

Vue + Element UI 实现权限管理系统 (admin-ui)


Author: Savannah
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Savannah !
  TOC