一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
先看个例子
案例:运用element-ui实现含分页数据的请求;增加;删除等
mockjs文件夹的index.js
import Mock from 'mockjs'
const data = Mock.mock({
"list|20-60": [
{
"id": '@increment(1)',
"title": "@ctitle",
"content": "@cparagraph",
"add_time": "@date(yyyy-MM-dd hh:mm:ss)"
}
]
})
// 删除
Mock.mock('/api/delete/news', 'post', (options) => {
let body = JSON.parse(options.body)
const index = data.list.findIndex(item => item.id === body.id)
data.list.splice(index, 1)
return {
status: 200,
message: '删除成功',
list: data.list
}
})
// 添加
Mock.mock('/api/add/news', 'post', (options) => {
let body = JSON.parse(options.body)
data.list.push(Mock.mock({
"id": '@increment(1)',
"title": body.title,
"content": body.content,
"add_time": "@date(yyyy-MM-dd hh:mm:ss)"
}))
return {
status: 200,
message: '添加成功',
list: data.list
}
})
// 含有分页的数据列表,有需要接受的参数要使用正则匹配
// /api/get/news?pagenum=1&pagesize=10
Mock.mock(/\/api\/get\/news/, 'get', (options) => {
console.log(options)
// 获取传递的参数pageindex
const pagenum = getQuery(options.url,'pagenum')
// 获取传递的参数pagesize
const pagesize = getQuery(options.url,'pagesize')
// 截取数据的起始位置
const start = (pagenum-1)*pagesize
// 截取数据的终点位置
const end = pagenum*pagesize
// 计算总页数
const totalPage = Math.ceil(data.list.length/pagesize)
// 数据的起始位置:(pageindex-1)*pagesize 数据的结束位置:pageindex*pagesize
const list = pagenum>totalPage?[]:data.list.slice(start,end)
return {
status: 200,
message: '获取新闻列表成功',
list: list,
total: data.list.length
}
})
const getQuery = (url,name)=>{
const index = url.indexOf('?')
if(index !== -1) {
const queryStrArr = url.substr(index+1).split('&')
for(var i=0;i<queryStrArr.length;i++) {
const itemArr = queryStrArr[i].split('=')
console.log(itemArr)
if(itemArr[0] === name) {
return itemArr[1]
}
}
}
return null
}
App.vue
<template>
<div id="app">
<!-- 头部 -->
<h3 style="text-align: center">数据展示</h3>
<!-- 添加 -->
<el-row :gutter="20">
<el-col :span="8"
><el-input v-model="title" placeholder="请输入标题"></el-input
></el-col>
<el-col :span="8"
><el-input v-model="content" placeholder="请输入内容"></el-input
></el-col>
<el-col :span="8"
><el-button type="primary" @click="handelAdd">添加</el-button></el-col
>
</el-row>
<!-- 表格 -->
<template>
<el-table :data="tableData" style="width: 100%">
<!-- <el-table-column label="图片" width="120">
<template v-if="tableData[0]"
><img :src="tableData[0].img_url" width="100" height="100"
/></template>
</el-table-column> -->
<el-table-column prop="title" label="标题" width="160">
</el-table-column>
<el-table-column prop="content" label="内容"> </el-table-column>
<el-table-column prop="add_time" label="时间" width="160">
</el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button @click="handleDelete(scope.row.id)" type="danger"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</template>
<el-button type="primary" @click="prev">上一页</el-button>
<el-button type="primary" @click="next">下一页</el-button>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
tableData: [],
title: "",
content: "",
pagenum: 1,
pagesize: 10,
total: 0
};
},
methods: {
// 获取数据列表
async getList() {
// axios.get("/api/get/news").then(res => (this.tableData = res.data.list));
const result = await axios.get("/api/get/news",{params: {pagenum: this.pagenum, pagesize: this.pagesize}})
this.tableData = result.data.list
this.total = result.data.total
},
// 删除
async handleDelete(id) {
const result = await axios.post("/api/delete/news", { id });
this.getList();
},
// 添加数据
async handelAdd() {
if (!this.title || !this.content) {
alert("请输入内容");
return;
}
const result = await axios.post("/api/add/news", {
title: this.title,
content: this.content
});
this.getList();
this.title = "";
this.content = "";
},
prev(){
if(this.pagenum > 1){
this.pagenum --
this.getList()
}
},
next(){
if(this.pagenum * this.pagesize < this.total ){
this.pagenum ++
this.getList()
}else{
alert('没有更多的数据')
}
}
},
created() {
this.getList();
}
};
</script>
main.js
import './mockjs/index'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
概念
什么是mockJs
生成随机数据,拦截 Ajax 请求
为什么使用mockJs
如果后端接口还未开发完成,我们自己手动模拟后端接口返回随机数据完成交互功能
- 采用json数据模拟,生成数据比较繁琐,也比较有局限性,没办法达到增删改查
- 采用mockJs进行模拟数据,可以模拟各种场景(get、post)生成接口,并且随机生成所需数据,还可以对数据进行增删改查
mock优点
1、前后端分离
让前端工程师独立于后端进行开发。
2、增加测试的真实性
通过随机数据,模拟各种场景。
3、开发无侵入
不需要修改既有代码,就可以拦截Ajax请求,返回模拟的响应数据。
4、用法简单
符合直觉的接口。
5、数据类型丰富
支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等。
6、方便扩展
支持支持扩展更多数据类型,支持自定义函数和正则。
7、在已有接口文档的情况下,我们可以直接按照接口文档来开发,将相应的字段写好,在接口完成 之后,只需要改变url地址即可。
8、不涉及跨域问题,
使用mockJs
通过vue-cli创建基本项目
-
在项目中安装mock
npm install mockjs -
在项目中新建mock文件夹,在mock文件夹中创建index.js
//引入mock模块 import Mock from 'mockjs'; -
将mock文件夹的index.js文件在main.js中导入
import Vue from 'vue' import App from './App.vue' import './mock/index.js' new Vue({ render: h => h(App), }).$mount('#app')
mock语法
生成字符串
-
生成指定次数字符串
const data = Mock.mock({ "string|4": "yx!" }) console.log(data) -
生成指定范围长度字符串
const data = Mock.mock({ "string|1-8": "yx" }) console.log(data)
生成文本
-
生成一个随机字符串
const data = Mock.mock({ "string": "@cword" }) console.log(data) -
生成指定长度和范围
const data = Mock.mock({ string: "@cword(1)", str: '@cword(10,15)' }) console.log(data)
生成标题和句子
-
生成标题和句子
const data = Mock.mock({ title: "@ctitle", sentence: '@csentence' }) console.log(data) -
生成指定长度的标题和句子
const data = Mock.mock({ title: "@ctitle(8)", sentence: '@csentence(50)' }) -
生成指定范围的
const data = Mock.mock({ title: "@ctitle(5,8)", sentence: '@csentence(50,100)' }) console.log(data)
生成段落
-
随机生成段落
const data = Mock.mock({ content: '@cparagraph()' }) console.log(data)
生成数字
-
生成指定数字
const data = Mock.mock({ "number|80": 1 }) console.log(data) -
生成范围数字
const data = Mock.mock({ "number|1-999": 1 }) console.log(data)
生成增量id
-
随机生成标识
const data = Mock.mock({ id: '@increment()' }) console.log(data)
生成姓名-地址-身份证号
-
随机生成姓名-地址-身份证号
const data = Mock.mock({ name: '@cname()', idCard: '@id()', address: '@city(true)' // 如果@city(),只会生成市,如果@city(true)会生成省和市 }) console.log(data)
随机生成图片
-
生成图片:
-
参数1:图片可选大小
-
参数2:图片背景色
-
参数3:图片前景色
-
参数4:图片格式
-
参数5:图片文字
const data = Mock.mock({ image: "@image('300x300', '#50B347', '#FFF', 'Mock.js')" }) console.log(data)
生成时间
-
@Date
-
生成指定格式时间:@date(yyyy-MM-dd hh:mm:ss)
const time = Mock.mock({ time1: '@date()', // 只有年月日 time2: '@date(yyyy-MM-dd hh:mm:ss)' }) console.log(time)
指定数组返回的条数
-
指定长度:'data|5'
-
指定范围:'data|5-10'
const data = Mock.mock({ 'list|50-99':[ { name: '@cname()', address: '@city(true)', id: '@increment(1)' // 每次都增加1 } ] })
mock拦截请求
-
在项目中安装axios
npm install axios -
在 main.js 文件引入
import axios from 'axios' -
在mock文件夹的
index.js文件中写mock语法
定义不携带参数的get请求
Mock.mock('/api/get/user','get',()=>{
return {
status: 200,
message: '获取新闻列表数据成功'
}
})
定义post请求
Mock.mock('/api/post/user','post',()=>{
return {
status: 200,
message: '添加新闻列表数据成功'
}
})
- 在 App.vue 文件发送请求
<template>
<div id="app">
</div>
</template>
<script>
export default {
created() {
axios.get('/api/get/user')
.then(function (response) {
console.log(response);
}),
axios.post('/api/post/user')
.then(res => console.log(res)),
}
}
</script>
<style lang="less" scoped>
</style>
Mock.mock()
- Mock.mock( requestUrl?, requestType?, template|function(options) )
- Mock.mock( template )
- Mock.mock( requestUrl, template )
- Mock.mock( requestUrl, requestType, template )
- Mock.mock( requestUrl, requestType, function(options) )
requestUrl: 要拦截的URL,字符串或正则表达式 equestType: 要拦截的请求类型,get/post/put/delete/options... template: 数据模板 function(options):生成响应数据的函数,options --> { url, type, body }
语法规范
数据模板定义
数据模板中每个属性由3部分组成: 属性名|生成规则:属性值
- 'name|min-max': value
- 'name|count': value
- 'name|min-max.dmin-dmax': value
- 'name|min-max.dcount': value
- 'name|count.dmin-dmax': value
- 'name|count.dcout': value
- 'name|+step': value
属性值中可以包含@占位符 属性值还指定了最终值的初始值和类型
1.属性值是字符串
- 'name|min-max': string
通过重复 string 生成一个字符串,重复次数大于等于 min,小于等于 max
- 'name|count': string
通过重复 string 生成一个字符串,重复次数等于 count
2.属性值是数字
- 'name|+1': number
属性值自动加 1,初始值为 number
- 'name|min-max': number
生成一个大于等于 min、小于等于 max 的整数,属性值 number 只是用来确定类型
- 'name|min-max.dmin-dmax': number
生成一个浮点数,整数部分大于等于 min、小于等于 max,小数部分保留 dmin 到 dmax 位
3.属性值是布尔值
- 'name|1': boolean
随机生成一个布尔值,值为 true 的概率是 1/2,值为 false 的概率同样是 1/2
- 'name|min-max': value
随机生成一个布尔值,值为 value 的概率是 min / (min + max),值为 !value 的概率是 max / (min + max)
4.属性值是对象
- 'name|count': object
从属性值 object 中随机选取 count 个属性
- 'name|min-max': object
从属性值 object 中随机选取 min 到 max 个属性
5.属性值是数组
- 'name|1': array
从属性值 array 中随机选取 1 个元素,作为最终值
- 'name|+1': array
从属性值 array 中顺序选取 1 个元素,作为最终值
- 'name|min-max': array
通过重复属性值 array 生成一个新数组,重复次数大于等于 min,小于等于 max
- 'name|count': array
通过重复属性值 array 生成一个新数组,重复次数为 count
6.属性值是函数
- 'name': function
执行函数 function,取其返回值作为最终的属性值,函数的上下文为属性 'name' 所在的对象
7.属性值是正则表达式
- 'name': regexp
根据正则表达式 regexp 反向生成可以匹配它的字符串。用于生成自定义格式的字符串
数据占位符定义
- 用 @ 来标识其后的字符串是 占位符
- 占位符 引用的是 Mock.Random 中的方法
- 通过 Mock.Random.extend() 来扩展自定义占位符
- 占位符 也可以引用 数据模板 中的属性
- 占位符 会优先引用 数据模板 中的属性
- 占位符 支持 相对路径 和 绝对路径
Mock.setup()
配置Ajax请求的行为,暂时支持的配置项有timeout
Mock.setup({
timeout: 500
})
Mock.setup({
timeout: '100-600'
})
Mock.Random
const Random = Mock.Random
Random.email() // => sd.sdf@oksd.com
Mock.mock('@email') // => sd.sdf@oksd.com
Mock.mock({ email: 'sd.sdf@oksd.com' }) // => { email: "sd.sdf@oksd.com" }
Mock.Random提供的完整方法(占位符):
| Type | Method |
|---|---|
| Basic | boolean, natural, integer, float, character, string, range, date, time, datetime, now |
| Image | image, dataImage |
| Color | color |
| Text | paragraph, sentence, word, title, cparagraph, csentence, cword, ctitle |
| Name | first, last, name, cfirst, clast, cname |
| Web | url, domain, email, ip, tld |
| Address | area(region, province, city(bool), county(bool), zip), region |
| Helper | capitalize(首字母大写), upper(大写), lower(小写), pick(从数组任取一个), shuffle(打乱数组元素顺序) |
| Miscellaneous | guid, id |
Basic
- Random.boolean(min?, max?, current? ) 返回一个随机的布尔值。
- Random.natural(min?, max? ) 返回一个随机的自然数
- Random.integer(min?, max? ) 返回一个随机的整数。
- Random.float( min?, max?, dmin?, dmax? ) 返回一个随机的浮点数。
- Random.character( pool? ) // pool => lower/upper/number/symbol 返回一个随机字符。
- Random.string( pool?, min?, max? ) // pool => lower/upper/number/symbol 返回一个随机字符串。
- Random.range( start?, stop, step? ) 返回一个整型数组。
Date
- Random.date( format? )
| 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 | 01 to 12 |
| h | 12-hour format of an hour with leading zeros | 1 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 |
- Random.time( format? ) 返回一个随机的时间字符串。
- Random.datetime( format? ) 返回一个随机的日期和时间字符串。
- Random.now( unit?, format? ) // unit => year、month、week、day、hour、minute、second、week
Image
Random.image()
- Random.image()
- Random.image( size )
- Random.image( size, background )
- Random.image( size, background, text )
- Random.image( size, background, foreground, text )
- Random.image( size, background, foreground, format, text )
Random.dataImage()
- Random.dataImage() base64
- Random.dataImage( size )
- Random.dataImage( size, text )
Color
- Random.color() // => #3538B2 随机生成一个有吸引力的颜色,格式为 '#RRGGBB'。
- Random.hex() // => #3538B2
- Random.rgb() // => rgb(242, 198, 121)
- Random.rgba() // => rgba(242, 198, 121, 0.13)
- Random.hsl() // => hsl(345, 82, 71)
Text
- Random.paragraph( min?, max? ) 随机生成一段文本。 句子个数(min = 3, max = 7)
- Random.cparagraph( min?, max? ) 随机生成一段中文文本
- Random.sentence( min?, max? ) 随机生成一个句子,第一个单词的首字母大写。
- Random.csentence( min?, max? ) 随机生成一段中文文本。
- Random.word( min?, max? ) 随机生成一个单词。
- Random.cword( pool?, min?, max? ) 随机生成一个汉字 (pool:汉字字符串。表示汉字字符池,将从中选择一个汉字字符返回。)
- Random.title( min?, max? ) 随机生成一句标题,其中每个单词的首字母大写。
- Random.ctitle( min?, max? ) 随机生成一句中文标题。
Name
- Random.first() 英文
- Random.last()
- Random.name( middle? )
- Random.cfirst() 中文
- Random.clast()
- Random.cname()
Web
-
Random.url( protocol?, host? ) 随机生成一个 URL。(protocol:指定 URL 协议。例如 http;host:指定 URL 域名和端口号。例如 nuysoft.com。)
-
Random.protocol() 随机生成一个 URL 协议。返回以下值之一
'http'、'ftp'、'gopher'、'mailto'、'mid'、'cid'、'news'、'nntp'、'prospero'、'telnet'、'rlogin'、'tn3270'、'wais'。
-
Random.domain() 随机生成一个域名。
-
Random.tld() 随机生成一个顶级域名
-
Random.email( domain? ) 随机生成一个邮件地址。
-
Random.ip() 随机生成一个 IP 地址。
Address
- Random.region() 随机生成一个(中国)大区。
- Random.province() 随机生成一个(中国)省(或直辖市、自治区、特别行政区)。
- Random.city( prefix? ) 随机生成一个(中国)市。(prefix:指定所属省份)
- Random.county( prefix? ) 随机生成一个(中国)县。 (prefix:指定所属的省、市)
- Random.zip() 随机生成一个邮政编码(六位数字)。
Helper
- Random.capitalize( word ) 把字符串的第一个字母转换为大写。
- Random.upper( str ) 把字符串转换为大写。
- Random.lower( str ) 把字符串转换为小写。
- Random.pick( arr ) 从数组中随机选取一个元素,并返回。
- Random.shuffle( arr ) 打乱数组中元素的顺序,并返回。
Miscellaneous
- Random.guid() 随机生成一个 GUID。
- Random.id() 随机生成一个 18 位身份证。
- Random.increment( step? ) 生成一个全局的自增整数。(step:整数自增的步长。默认值为 1)
扩展
Random.extend({
fruit () {
const fruit = ['apple', 'peach', 'lemon']
return this.pick(fruit)
}
})
Random.fruit() // => 'peach'
Mock.mock('@fruit') // => 'lemon'
Mock.mock({
fruit: '@fruit' // => 'peach'
})
Mock.valid( template, data )
校验真实数据 data 是否与数据模板 template 匹配。
template
必选。 表示数据模板,可以是对象或字符串。例如 { 'list|1-10':[{}] }、'@EMAIL'。
data
必选。 表示真实数据。
var template = {
name: 'value1'
}
var data = {
name: 'value2'
}
Mock.valid(template, data)
// =>
[ { "path": [ "data", "name" ],
"type": "value",
"actual": "value2",
"expected": "value1",
"action": "equal to",
"message": "[VALUE] Expect ROOT.name'value is equal to value1, but is value2"
}
]
Mock.toJSONSchema()
Mock.toJSONSchema( template )
把 Mock.js 风格的数据模板 template 转换成 JSON Schema (template:必选 表示数据模板,可以是对象或字符串)
var template = {
'key|1-10': '★'
}
Mock.toJSONSchema(template)
// =>
{
"name": undefined,
"path": [
"ROOT"
],
"type": "object",
"template": {
"key|1-10": "★"
},
"rule": {},
"properties": [{
"name": "key",
"path": [
"ROOT",
"key"
],
"type": "string",
"template": "★",
"rule": {
"parameters": ["key|1-10", "key", null, "1-10", null],
"range": ["1-10", "1", "10"],
"min": 1,
"max": 10,
"count": 3,
"decimal": undefined,
"dmin": undefined,
"dmax": undefined,
"dcount": undefined
}
}]
}
var template = {
'list|1-10': [{}]
}
Mock.toJSONSchema(template)
// =>
{
"name": undefined,
"path": ["ROOT"],
"type": "object",
"template": {
"list|1-10": [{}]
},
"rule": {},
"properties": [{
"name": "list",
"path": ["ROOT", "list"],
"type": "array",
"template": [{}],
"rule": {
"parameters": ["list|1-10", "list", null, "1-10", null],
"range": ["1-10", "1", "10"],
"min": 1,
"max": 10,
"count": 6,
"decimal": undefined,
"dmin": undefined,
"dmax": undefined,
"dcount": undefined
},
"items": [{
"name": 0,
"path": ["data", "list", 0],
"type": "object",
"template": {},
"rule": {},
"properties": []
}]
}]
}
感谢
谢谢你读完本篇文章,希望对你能有所帮助,如有问题欢迎各位指正。
我是Nicnic,如果觉得写得可以的话,请点个赞吧❤。
写作不易,「点赞」+「在看」+「转发」 谢谢支持❤