Mock.js 快速上手攻略:手把手教你学会使用 Mock.js
参考文章:【mockJs 妈妈再也不用担心我没有后端接口啦】
初识 Mock.js
Mock.js 官网:http://mockjs.com/
注意:Mock.js 早在几年之前就不再更新维护,建议非必要不使用它。
Mock.js 是模拟数据的第三方库,它是一个用于生成随机数据和拦截 Ajax 请求的 JavaScript 库,非常适合在前端开发中模拟后端 API 和生成大量测试数据。
使用场景:在项目中拦截请求,构造假数据。
Mock.js 的主要功能包括:
生成随机数据:通过定义数据模板,Mock.js 可以生成各种类型的随机数据,例如文字、数字、日期和自定义格式。
拦截 Ajax 请求:Mock.js 可以捕获和模拟 Ajax 请求,返回模拟的响应数据,这对于前端开发和测试非常有用,尤其是在后端服务尚未开发完成时。
Mock.js 简单使用步骤
安装 Mock.js:在你的项目中,首先需要安装 Mock.js。打开终端,进入你的项目目录,然后运行以下命令:
npm install mockjs
# 如果是TS项目,则还需执行下面的命令
npm install -D @types/mockjs
创建 Mock 数据规则:在项目中创建一个专门的目录(例如 src/mocks),用于存放所有的 Mock 数据规则和配置。创建一个简单的 Mock 规则文件 。src/mocks/index.js:
import { mock } from 'mockjs'
const data = mock({
"status": 200,
'data|1-10': [{
'id|+1': 1,
'name': '@name', // 随机生成名字
'age|18-60': 1 // 随机生成18至60之间的数字
}]
})
console.log('Mock.js is loaded and mock API is set.')
console.log(data)
Mock 之生成随机数据
更多使用示例介绍 __ 数据模板定义、数据占位符参考示例:http://mockjs.com/examples.html
1. 数据模板定义规范
数据模板中每个属性由 3 部分构成:属性名、生成规则、属性值,数据模版格式如下:
"属性名|生成规则": 属性值
属性名:用来指定生成数据的规则,可以加上规则字符串来控制生成的数据。
属性值:用来指示生成数据的类型和内容,可以是具体的值、类型占位符、或者函数。
1.1. 生成规则
生成规则有以下 7 种格式:
'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.dcount': value
'name|+step': value
dmin 最少小数位,dmax 最多小数位
step 递增
dcount 固定位数的小数位
1.2. String
'name|min-max': string 重复string,次数为min-max
'name|count': string 重复string,次数为 count
// string 值是字符串
"name1|1-10": 'a', // 重复 1-10 次,每次重复的字符串为 'a'
"name2|3": '**', // 重复 3 次,每次重复的字符串为 '**'
1.3. Number
'name|+1': number 值加1,初始值为number
'name|min-max': number 生成一个 min-max 之间的整数
'name|min-max.dmin-dmax': number 生成一个浮点数,整数部分在 min-max 之间,小数部分保留 dmin-dmax 位
'name|count.dcount: number 生成一个整数部分为 count,小数部分保留 dcount 位的小数
"numberList|3": [
{
// number 值是数字
"number1|+1": 1, // 递增,从 1 开始递增 1
"number2|1-5": 1, // 范围随机,随机生成 1-5 之间的数字
"number3|1-100.1-10": 1, // 随机小数,整数部分1-100,小数部分1-10位 =》 随机生成 1-100 之间的小数,小数点后 1-10 位
"number4|1.1-10": 1, // 随机小数,整数部分1,小数部分1-10位 =》 随机生成 1-10 之间的小数
"number5|1.1": 1, // 随机小数,整数部分1,小数部分保留1位 =》 随机生成 1-10 之间的小数
}
]
1.4. Boolean
name|1': boolean 随机生成一个布尔值,值为 true 的概率为 1/2
name|min-max': boolean 随机生成一个布尔值,值为 boolean 的概率是 min / (min + max),值为 !boolean 的概率是 max / (min + max)
// boolean 值是布尔
"boolean1|1": true, // 随机生成 true 或 false, 值为 true 的概率为 1/2
"boolean2|1-2": false, // 随机生成一个布尔值,值为 false 的概率是 1/3 min / (min + max),值为 true 的概率是 2/3 max / (min + max)
1.5. Object
'name|count': object 从属性值 object 中随机选取 count 个属性
'name|min-max': object 从属性值 object 中随机选取 min-max 个属性
// object 值是对象
"object1|2": {
name: "张三",
age: 18,
sex: "男"
},
"object2|1-2": {
name: "张三",
age: 18,
sex: "男",
address: "北京市东城区"
}
1.6. Array
'name|1': array 从属性值 array 中随机选取 1 个元素,作为最终值
'name|+1': array 从属性值 array 中 顺序 选取 1 个元素,作为最终值
'name|min-max': array 通过重复属性值 array 生成一个新数组,重复次数为 [min,max]
'name|count': array 通过重复属性值 array 生成一个新数组,重复次数为 count
// array 值是数组
"array1|1": [1,2,3,4,5],
"array2|+1": [1,2,3,4,5],
"array3|1-3": [1,2,3,4,5],
"array4|3": [1,2,3,4,5]
1.7. Function
'name': function 执行这个函数
// function 值是函数
'function': function() {
return '张三'
}
1.8. RegExp
'name': regexp 根据正则表达式 regexp 反向生成可以匹配它的字符串。用于生成自定义格式的字符串
// regexp 值是正则
"regexp|2":[
{
"email": /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/,
"phone": /^1[3456789]\d{9}$/,
"idCard": /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
"ip": /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/,
}
]
1.9. Path
Absolute Path
Relative Path
2. 数据占位符
数据占位符参考示例:http://mockjs.com/examples.html#DPD
Mock.js 内置了丰富的数据占位符用于生成各种类型和格式的数据。这些占位符通常以 @ 符号开头。
占位符 只是在属性值字符串中占个位置,并不出现在最终的属性值中。
用 @来标识占位符
占位符引用的是 Mock.Random 中的方法
Mock.Random.extend () 来扩展自定义占位符
占位符 会优先引用 数据模板 中的属性
占位符 支持 相对路径 和 绝对路径
占位符 格式:
@占位符
@占位符(参数)
数据占位符使用:
Random.xxx()// 使用 Random 函数, xxx 为 random 对应方法
Mock.mock ('@xxx') // 使用占位符,对应 @xxx 的占位符
2.1. Random 方法总结
// Basic: boolean natural integer float character string range
Random.boolean() // 随机布尔值
Random.natural( min?, max? ) // 随机自然数 min-max之间
Random.integer( min?, max? ) // 随机整数 min-max之间
Random.float( min?, max?, dmin?, dmax? ) // 随机浮点数
Random.character( pool? ) // 随机字母 pool对应有(lower[小写]/upper[大写]/number[数字]/symbol[符号])
Random.string( pool?, min?, max? ) // 随机字符串
Random.range(start?, stop, step?) // 随机范围数字组成的数组
// Date: date time datetime now
Random.date( format? ) // 随机日期
Random.time( format? ) // 随机时间
Random.datetime( format? ) // 随机日期+时间
Random.now( unit?, format? ) // 当前时间
// Image: image dataImage
Random.image( size?, background?, foreground?, format?, text? ) // 图片占位
Random.dataImage( size?, text? ) // 生成base64格式图片
// Color: color hex rgb rgba hsl
Random.color() // 随机颜色
Random.hex()
Random.rgb() // 随机rgb颜色
Random.rgba() // rgba颜色值
Random.hsl()
// Text: paragraph sentence word title cparagraph csentence cword ctitle
Random.paragraph( min?, max? ) // 段落
Random.sentence( min?, max? )
Random.word( min?, max? )
Random.title( min?, max? )
Random.cparagraph( min?, max? ) // 中文段落
Random.csentence( min?, max? ) // 中文句子
Random.cword( pool?, min?, max? ) // 汉字
Random.ctitle( min?, max? ) // 标题
// Name: first last name cfirst clast cname
Random.first() // 姓
Random.last() // 名
Random.name( middle? ) // 姓名
Random.cfirst() // 中文姓
Random.clast() // 中文名
Random.cname() // 中文姓名
// Web: url domain protocol tld email ip
Random.url() // 随机URL
Random.domain() // 随机域名
Random.protocol() // 随机网络协议
Random.tld() // 随机顶级域名
Random.email() // 邮箱
Random.ip()
// Address: region province city county zip
Random.region()
Random.province() // 省
Random.city( prefix? ) // 市 (prefix是否带前缀省,值为boolean)
Random.county( prefix? ) // 区县 (prefix是否带缀省,市)
Random.zip() // 邮政编码
// Helper: capitalize upper lower pick shuffle
Random.capitalize( word ) // 转换首字母大写
Random.upper( str ) // 转换为大写字母
Random.lower( str ) // 转换为小写字母
Random.pick( arr ) // 数组中随机选择一个元素返回
Random.shuffle( arr ) // 数组元素随机打乱顺序后返回新数组
// Miscellaneous: guid id increment
Random.guid() // 返回一个新的全局唯一标识符(GUID/UUID)
Random.id() // 返回一个仿真的身份证号码(模拟中国的身份证格式)
Random.increment( step? ) // 递增,生成一个递增的数字,每次调用时根据指定的步长 step 增加
以下是一些常用的占位符类别及示例:
2.2. Basic
Random.boolean() // 随机布尔值
Random.natural( min?, max? ) // 随机自然数 min-max之间
Random.integer( min?, max? ) // 随机整数 min-max之间
Random.float( min?, max?, dmin?, dmax? ) // 随机浮点数
Random.character( pool? ) // 随机字母 pool对应有(lower[小写]/upper[大写]/number[数字]/symbol[符号])
Random.string( pool?, min?, max? ) // 随机字符串
Random.range(start?, stop, step?) // 随机范围数字组成的数组
"布尔值": Random.boolean(),
"自然数": Random.natural(1, 10), // 1 到 10 之间的自然数
"整数": Random.integer(1, 100), // 1 到 100 之间的整数
"浮点数": Random.float( 0, 10, 2, 2 ), // 0 到 10 之间,小数部分保留 2 位的浮点数
"小写字母": Random.character( "lower" ), // 随机字母 (lower[小写]/upper[大写]/number[数字]/symbol[符号])
"符号": Random.character( "symbol" ), // 随机生成符号
"字符串": Random.string( "lower", 5, 10 ), // 随机生成字符串
"数组": Random.range(1, 10,2) // 1开始到10结束,步长为2
2.3. Date
时间日期类
@date("yyyy-MM-dd"):生成符合格式的日期。
@time("HH:mm:ss"):生成符合格式的时间。
@datetime("yyyy-MM-dd HH:mm:ss"):生成符合格式的日期和时间。
Random.date( format? ) // 随机日期
Random.time( format? ) // 随机时间
Random.datetime( format? ) // 随机日期+时间
Random.now( unit?, format? ) // 当前时间
"日期": Random.date(),
"时间": Random.time(),
"日期+时间": Random.datetime('"yyyy-MM-dd HH:mm:ss"'),
"当前时间": Random.now()
2.4. *Image
图片网站:Dynamic Dummy Image Generator
@image( size?, background?, foreground?, format?, text? )
size 尺寸 background 背景色 foreground 前景色 format 后缀 text 文本
图像类
@image('200x100', '#FFCC33', '#FFF', 'png', 'Hello'):生成一个尺寸为200x100,背景色为#FFCC33,前景色为#FFF,格式为png的图像,图像中的文本为Hello。
Random.image( size?, background?, foreground?, format?, text? ) // 图片占位
Random.dataImage( size?, text? ) // 生成base64格式图片
import {mock, Random} from 'mockjs'
const data = mock({
"imgList|3": [
{
"img1": "@image( '200x100', '#FFCC33', '#FFF', 'png', 'Hello' )",
"img2": Random.image( '200x100', '#FFCC33', '#FFF', 'png', 'Hello' )
}
]
})
console.log('Mock.js is loaded and mock API is set.')
console.log(data)
2.5. Color
颜色类
Random.color() // 随机颜色十六进制
Random.hex()
Random.rgb() // 随机rgb颜色
Random.rgba() // rgba颜色值
Random.hsl()
"颜色1": Random.color(),
"颜色2": Random.hex(),
"颜色3": Random.rgb(),
"颜色4": Random.rgba(),
"颜色5": Random.hsl()
2.6. Text
文本类
@sentence(3, 5):生成一个包含 3 到 5 个单词的句子。
@title(1, 3):生成一个 1 到 3 个单词的标题。
@word(3, 5):生成一个长度在 3 到 5 之间的单词。
Random.paragraph( min?, max? ) // 段落
Random.sentence( min?, max? )
Random.word( min?, max? )
Random.title( min?, max? )
Random.cparagraph( min?, max? ) // 中文段落
Random.csentence( min?, max? ) // 中文句子
Random.cword( pool?, min?, max? ) // 汉字
Random.ctitle( min?, max? ) // 标题
2.7. Name
名字类
@name:生成一个常见的名字。
Random.first() // 姓
Random.last() // 名
Random.name( middle? )
// 姓名
Random.cfirst() // 中文姓
Random.clast() // 中文名
Random.cname() // 中文姓名
"姓": Random.first(),
"名": Random.last(),
"姓名": Random.name(),
"中文姓": Random.cfirst(),
"中文名": Random.clast(),
"中文姓名": Random.cname()
2.8. Web
网址类
@url:生成一个 URL。
Random.url() // 随机URL
Random.domain() // 随机域名
Random.protocol() // 随机网络协议
Random.tld() // 随机顶级域名
Random.email() // 邮箱
Random.ip()
"url": Random.url('https'),
"域名": Random.domain(),
"协议": Random.protocol(),
"顶级域名": Random.tld(),
"邮箱": Random.email('gmail.com'),
"ip": Random.ip()
2.9. Address
地址类
Random.region()
Random.province() // 省
Random.city( prefix? )
// 市 (prefix是否带前缀省,值为boolean)
Random.county( prefix? )
// 区县 (prefix是否带缀省,市)
Random.zip() // 邮政编码
"地域": Random.region(),
"省份": Random.province(),
"市区": Random.city(),
"区县": Random.county(),
"邮编": Random.zip()
2.10. 扩展占位符
import {mock, Random} from 'mockjs'
Random.extend({
names: function () {
return this.name() + '-' + this.cname()
},
bili: function () {
return this.pick(['点赞','投币','关注'])
}
})
const data = mock({
"status": 200,
'data|1-10': [{
'name': '@names',
'bili': '@bili'
}]
})
console.log('Mock.js is loaded and mock API is set.')
console.log(data)
Mock 之拦截请求
1. 拦截 axios 请求示例
1.1. 简单示例
前置条件:注意务必确保项目中已安装了 axios、mockjs 依赖。
封装 axios:这是封装好的 axios 请求(路径为 /src/api/index.ts ):
import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:3000'
export default axios
mock 拦截:/src/mocks/mock.ts,注意确保请求地址前缀与 axios 设置的 baseURL 保持一致
import { mock } from 'mockjs'
mock('http://localhost:3000/users', {
"status": 200,
"message": "success",
"data|3-10": [
{
"id|+1": 1,
"name": "@name",
"age|18-30": 1,
"address": "@county(true)"
}
]
})
调用接口测试:在 App.vue 首页中调用接口,此处通过控制台打印可看到模拟的数据
<script setup lang="ts">
import { RouterView } from 'vue-router'
import {onMounted} from "vue"
import axios from '@/api/index'
import '@/mocks/mock'
const getUsers = async () => {
const res = await axios.get('/users')
console.log(res.data)
}
onMounted(()=>{
getUsers()
})
</script>
<template>
<div id="app">
<RouterView />
</div>
</template>
<style scoped>
#app {
width: 100vw;
height: 100vh;
box-sizing: border-box;
display: flex;
flex-flow: column nowrap;
}
</style>
1.2. 拦截的几种写法
1.2.1. 完整匹配
import axios from "axios"
import { mock } from 'mockjs'
mock('http://localhost:3000/users', {
"status": 200,
"message": "success",
"data|3-10": [
{
"id|+1": 1,
"name": "@name",
"age|18-30": 1,
"address": "@county(true)"
}
]
})
const getUsers = async () => {
const res = await axios.get('/users')
console.log(res.data)
}
getUsers()
1.2.2. method
import { mock } from 'mockjs'
mock('http://localhost:3000/users', "get", {
"status": 200,
"message": "success",
"data|3-10": [
{
"id|+1": 1,
"name": "@name",
"age|18-30": 1,
"address": "@county(true)"
}
]
})
1.2.3. 正则
import { mock } from 'mockjs'
mock(/.*?\/users/, {
"status": 200,
"message": "success",
"data|3-10": [
{
"id|+1": 1,
"name": "@name",
"age|18-30": 1,
"address": "@county(true)"
}
]
})
1.2.4. 函数模式
import { mock } from 'mockjs'
import type { MockjsRequestOptions } from 'mockjs'
mock(/.*?\/users/, "post", function(options: MockjsRequestOptions){
console.log(options)
return {
"status": 200,
"message": "success",
"data|3-10": [
{
"id|+1": 1,
"name": "@name",
"age|18-30": 1,
"address": "@county(true)"
}
]
}
})
2. 拦截增删改查接口示例
import {mock} from 'mockjs'
import type { MockjsRequestOptions } from 'mockjs'
mock(/.*?\/users/, "get", {
"status": 200,
"message": "success",
"data": [
{
"name": "@name",
"age|18-30": 1,
"address": "@county(true)"
}
]
})
mock(/.*?\/users/, "post", function (options: MockjsRequestOptions){
console.log('post请求', options)
return {
"status": 200,
"message": "添加成功",
"data": {}
}
})
mock(/.*?\/users\/\d+/, "put", function (options: MockjsRequestOptions){
console.log('put请求', options)
return {
"status": 200,
"message": "更新成功",
"data": {}
}
})
mock(/.*?\/users\/\d+/, "delete", {
"status": 200,
"message": "删除成功",
"data": {}
})
const getUsers = async () => {
let res = await axios.get('/users')
console.log("get", res.data)
res = await axios.post('/users', {name: '张三'})
console.log("post", res.data)
res = await axios.put('/users/1', {name: '李四'})
console.log("put", res.data)
res = await axios.delete('/users/1')
console.log("delete", res.data)
}
getUsers()
实际应用:Vue3 项目中使用 Mock.js
在一个使用 Vue 3 和 TypeScript 的项目中整合 Mock.js 来模拟数据是一个常见的开发实践,尤其是在项目的早期阶段或者当后端接口尚未定义或完成时。这可以帮助前端开发者独立于后端进行开发和测试。
前置条件:创建 Vue 项目
我们开始之前,一定要确保 Vue 项目已创建,并且我们需要安装 axios 与 ts 依赖,如果未创建项目的请参考下面命令创建。
更多关于 TypeScript 请参考:Vue3 引入 TypeScript
# 创建 Vue 项目
npm create vue@latest
# 安装 axios 依赖
npm install axios
# 安装 TS(如果项目中没有的话)
npm install --save-dev typescript
npm install --save-dev @vue/cli-plugin-typescript
步骤 1:安装 Mock.js
首先,打开您的终端,进入您的 Vue 3 项目目录,然后运行以下命令来安装 Mock.js:
npm install mockjs
# 如果是TS项目,则还需执行下面的命令
npm install -D @types/mockjs
步骤 2:配置 axios
项目主要的目录结构如下:
src
api
index.ts
users.ts
json
users.json
mocks
index.ts
users.ts
main.ts
App.vue
封装 axios 并新建用户接口文件:在项目 src 目录下新建 api 文件夹,用来处理接口调用信息。创建一个 index.ts、users.ts 文件来定义您的接口。
src/api/index.ts:
import axios from 'axios'
const baseURL = 'http://localhost:3000'
export const axiosInstance = axios.create({
baseURL: baseURL
})
export interface Response<T> {
status: number,
data: T,
message: string
}
axiosInstance.interceptors.request.use(
(request) => {
// request.headers['token'] = `xxx`
return request
},
(error) => {
return Promise.reject(error)
}
)
axiosInstance.interceptors.response.use(
(response) => {
if (response?.data.status === 200) {
return response?.data.data
}
},
(error) => {
console.error('接口错误',error)
return Promise.reject(error)
}
)
src/mocks/users.ts:
import {axiosInstance} from "@/api/index"
import type {Response} from '@/api/index'
const USER = '/users'
interface UserResponse {
readonly id: number
name: string
age: number
email?: string
password?: string
address?: string
}
export function getUsers():Promise<Response<UserResponse[]>> {
return axiosInstance.get(USER)
}
步骤 3:json-server 模拟真实 API
新建一个 users.json 文件,用于 json-server 启动本地 JSON 服务器测试接口使用。
src/json/users.json:
{
"users": {
"status": 200,
"message": "success",
"data": [
{
"id": 1,
"name": "Joe",
"age": 30,
"email": "joe@gmail.com",
"password": "123456",
"address": "123 Main St."
},
{
"id": 2,
"name": "Jane",
"age": 25,
"email": "jane@gmail.com",
"password": "123456",
"address": "456 Main St."
},
{
"id": 3,
"name": "John",
"age": 40,
"email": "john@gmail.com",
"password": "123456",
"address": "789 Main St."
},
{
"id": 4,
"name": "Jimmy",
"age": 35,
"email": "jimmy@gmail.com",
"password": "123456",
"address": "321 Main St."
}
]
}
}
启动 json-server:
json-server -w users.json
更多信息请参考:json-server
步骤 4:配置 Mock 数据
创建 Mock 文件: 在项目中,通常我们会创建一个专用的目录来存放 Mock 配置和数据。例如,在 src 目录下创建一个 mocks 目录,然后创建一个 index.ts、users.ts 文件来定义您的 Mock 规则。
src/mocks/index.ts:
import './users'
src/mocks/users.ts:
import {mock} from 'mockjs'
mock(/.*?\/users/, "get", {
"status": 200,
"message": "success",
// 生成3-10个用户数据
"data|3-10": [
{
"id|+1": 1,
"name": "@cname",
"age": "@integer(18,30)",
"email": "@email",
"password": "@string('number', 6)",
"address": "@city(true)"
}
]
})
在项目中引入 Mock.js: 在 src/main.ts 文件中引入 Mock.js 配置,以确保它在项目构建时被加载。src/main.ts:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
/**
* 开发环境下引入 Mock.js
* 因为是基于vite的项目,所以使用 import.meta.env.VITE_NODE_ENV,基于Vue CLI 的用process.env.NODE_ENV
* Mock.js 是异步加载 =》 确保应用在 Mock.js 准备好后启动
* */
const startApp = async () => {
if (import.meta.env.VITE_NODE_ENV === 'development') {
// import '@/mocks' 这是错误的 =》 因为 import 语句在 JavaScript 中是静态的,不能在运行时条件性地执行
await import('@/mocks')
}
app.mount('#app');
}
startApp()
这里使用条件导入(import())来确保只在开发环境中使用 Mock.js,防止在生产环境中引入。
步骤 5:使用 Mock 数据
在 Vue 组件中使用 Mock.js 模拟的 API 数据非常直接。这里在组件 App.vue 来展示如何获取和显示用户数据。
src/App.vue:
<script setup lang="ts">
import { RouterView } from 'vue-router'
import {onMounted, ref} from "vue"
import {getUsers} from '@/api/users'
const users = ref([]);
const selectUsers = async () => {
let res = await getUsers()
users.value = res
}
onMounted(()=>{
selectUsers()
})
</script>
<template>
<div id="app">
<div>
<h1>用户列表</h1>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.age }} years old
</li>
</ul>
</div>
<RouterView />
</div>
</template>
在这个组件中,我们使用 Vue 3 的 Composition API,通过 axios 发起 GET 请求到 /api/users。由于已经配置了 Mock.js 来拦截这个请求,所以请求将返回我们预先定义的模拟数据。
步骤 6:运行和测试
运行您的 Vue 应用,您将看到显示几个随机生成的用户信息。这证明 Mock.js 正在正常工作,并成功拦截和返回了模拟数据。
[步骤 7]:优化 _Mock 开关控制
变通一下,我们可以在页面中设置一个开关,当打开这个开关时就 Mock 模拟数据,关闭则取消。
新增 pinia 状态管理,/src/stores/mock.ts:
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useMockStore = defineStore('mock', () => {
// state =》 ref()
const isMock = ref(true)
// actions => function()
const toggleMock = (value) => {
isMock.value = value
}
return {
isMock,
toggleMock
}
})
src/main.ts:
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import 'vant/lib/index.css'
import { useMockStore } from "@/stores/mock"
const app = createApp(App)
app.use(createPinia())
app.use(router)
/**
* 开发环境下引入 Mock.js
* 因为是基于vite的项目,所以使用 import.meta.env.VITE_NODE_ENV,基于Vue CLI 的用process.env.NODE_ENV
* Mock.js 是异步加载 =》 确保应用在 Mock.js 准备好后启动
* */
const startApp = async () => {
if (import.meta.env.VITE_NODE_ENV === 'development' && useMockStore().isMock) {
// import '@/mocks' 这是错误的 =》 因为 import 语句在 JavaScript 中是静态的,不能在运行时条件性地执行
await import('@/mocks')
}
app.mount('#app');
}
startApp()
src/App.vue:
<script setup lang="ts">
import { RouterView } from 'vue-router'
import {onMounted, ref} from "vue"
import {getUsers} from '@/api/users'
import {useMockStore} from "@/stores/mock";
const users = ref([])
const {isMock, toggleMock} = useMockStore()
const changeSwitchMock = (value) => {
toggleMock(value)
value ? selectUsers() : clearUsers()
}
const clearUsers = () => {
users.value = []
}
const selectUsers = async () => {
let res = await getUsers()
users.value = res
}
onMounted(()=>{
isMock ? selectUsers() : ''
})
</script>
<template>
<div id="app">
<div class="switch-color">
<span class="text"> Mock 模拟 </span>
<van-switch v-model="isMock"
active-color="#07c160"
inactive-color="#dcdee0"
@change="changeSwitchMock"
/>
<van-button @click="changeSwitchMock" round icon="replay" plain type="primary" size="small">刷新</van-button>
</div>
<div>
<h1>用户列表</h1>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.age }} years old
</li>
</ul>
</div>
</div>
</template>
<style scoped>
#app {
width: 100vw;
height: 100vh;
box-sizing: border-box;
display: flex;
flex-flow: column nowrap;
}
.switch-color {
display: flex;
align-content: center;
.text {
align-self: center;
}
.van-switch {
align-self: center;
margin-right:10px;
}
}
</style>
通过这种方式,使用 Mock.js 在您的 Vue 3 + TypeScript 项目中帮助模拟后端 API,从而可以在后端尚未开发完成的情况下进行前端开发和测试。
实际应用:Vue3 项目中 Mock.js 本地模拟增删改查
使用 Mock.js 模拟 RESTful API 的增删改查 (CRUD) 操作是一种非常实用的方法,特别是在后端尚未开发完成时。这不仅可以帮助前端开发和测试,也可以在演示或原型阶段使用。以下是如何使用 Mock.js 来模拟这些操作的具体步骤。
1. 创建项目和初始化
创建 Vue 项目并安装必要的依赖:
# 创建 Vue 项目
npm create vue@latest
npm install axios mockjs
# 如果是TS项目,则还需执行下面的命令
npm install -D @types/mockjs
2. 配置 Mock.js
在项目中创建一个目录结构,用于存放 Mock 数据和配置:
src/
├── api/ # API 调用函数
│ ├── users.ts
├── mocks/ # Mock.js 配置和数据
│ ├── index.ts
│ ├── data
| | ├── users.ts # 初始 Mock 数据
│ ├── models
| | ├── User.ts # 定义用户数据类型
│ ├── services
| | ├── mockServices.ts # Mock.js 配置
└── views/ # 页面视图
2.1. Mock.js 数据和配置
src/mocks/index.ts:
import './services/mockService'
src/mocks/data/users.ts:
// 初始 Mock 数据 src/mocks/data/users.ts
import type { User } from '../models/User'
export const users: User[] = [
{
id: 'e1aEAEB1-e9C5-46a0-6Bb2-4dcCeeaD1F12',
name: '陆秀英',
age: 48,
email: 'r.abypkt@gmail.com',
address: '黑龙江省 绥化市 其它区'
},
{
id: '5fd1FD0b-F30b-36fc-6Ec4-5bd163AB47F7',
name: '顾桂英',
age: 59,
email: 'f.muwaj@gmail.com',
address: '西藏自治区 昌都地区 贡觉县'
},
{
id: '4f05f659-3cEd-6C9f-Ae79-5BBdD4CBd2EE',
name: '吴丽',
age: 47,
email: 'w.icy@gmail.com',
address: '香港特别行政区 九龙 油尖旺区'
}
]
src/mocks/models/User.ts:
// 定义用户数据类型 src/mocks/models/User.ts
export interface User {
id: string
name: string
age: number
email?: string
address?: string
}
src/mocks/services/mockService.ts:
// 设置 Mock 接口处理增删改查请求 src/mocks/services/mockService.ts
import { users } from '../data/users'
import type { User } from '../models/User'
import { mock, Random } from 'mockjs'
// 查
mock('/api/users', 'get', () => users)
// 增
mock('/api/users', 'post', (options: any) => {
const newUser: User = JSON.parse(options.body)
newUser.id = Random.guid()
users.push(newUser)
return { user: newUser }
})
// 删
mock(/\/api\/users\/[0-9a-fA-F\-]+/, 'delete', (options: any) => {
const id = options.url.split('/').pop()
const index = users.findIndex((u) => u.id === id)
users.splice(index, 1)
return { message: 'User deleted successfully' }
})
// 改
mock(/\/api\/users\/[0-9a-fA-F\-]+/, 'put', (options: any) => {
const id = options.url.split('/').pop()
const updates = JSON.parse(options.body)
const user = users.find((u) => u.id === id)
// Object.assign(target, ...source objects) 将源对象推入目标对象并显示目标对象
Object.assign(user, updates)
return { user }
})
2.2. 主入口引入 mock 配置
在 src/main.ts 中引入 mock 配置以确保它在应用加载前被加载:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './mocks' // 确保 mock 配置被加载
const app = createApp(App)
app.use(router)
app.mount('#app')
3. 创建 API 调用函数
src/api/users.ts:
import axios from 'axios'
import type { User } from '@/mocks/models/User'
export const getUsers = () => axios.get('/api/users')
export const addUser = (user: User) => axios.post('/api/users', user)
export const updateUser = (id: string, user: User) => axios.put(`/api/users/${id}`, user)
export const deleteUser = (id: string) => axios.delete(`/api/users/${id}`)
4. 创建和配置 Vue 组件
创建用户管理的 Vue 组件(例如 src/components/UsersComponent.vue)
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { User } from '@/mocks/models/User'
import { mock, Random } from 'mockjs'
import { addUser, deleteUser, getUsers, updateUser } from '@/api/users'
const users = ref<User[]>([])
onMounted(() => {
selectUsers()
})
const selectUsers = async () => {
const { data } = await getUsers()
users.value = data
}
const handleAdd = async () => {
const user = mock({
id: Random.guid(),
name: '@cname',
email: '@email',
age: '@integer(18, 50)',
address: '@city(true)'
})
await addUser(user)
await selectUsers()
}
const handleEdit = async (user: User) => {
const newUser = mock({
name: '@cname',
email: '@email',
age: '@integer(18, 50)',
address: '@city(true)'
})
await updateUser(user.id, newUser)
await selectUsers()
}
const handleDelete = async (id: string) => {
await deleteUser(id)
await selectUsers()
}
</script>
<template>
<!--显示用户列表和操作页面-->
<div>
<ul v-for="user in users" :key="user.id">
<li>{{ user.name }} - {{ user.email }}</li>
<button @click="handleDelete(user.id)">Delete</button>
<button @click="handleEdit(user)">Edit</button>
</ul>
<button @click="handleAdd">Add User</button>
</div>
</template>
<style scoped></style>
5. 使用组件
在你的主视图或任何其他地方引入并使用这个组件。
总结
通过使用 Mock.js 模拟后端 API,前端开发者可以在后端尚未实现这些接口时独立进行开发和测试。这种方法非常适合快速原型开发和功能演示。通过灵活的 Mock.js 配置,你可以模拟几乎任何类型的数据和行为,有效地支持复杂的前端应用开发。
😸Mock.js 的替代方案
前文中有提到,Mock.js 早在几年之前就不再更新维护,建议非必要不使用它。
如果你正在寻找 Mock.js 的替代方案,特别是考虑到 Mock.js 可能不再积极维护,下面几个流行的库,它们可以提供类似或更加先进的功能来模拟 HTTP 请求和响应:
1. Faker.js
GitHub 仓库: GitHub - faker-js/faker: Generate massive amounts of fake data in the browser and node.js
描述: 用于生成大量假数据的库,如姓名、地址、电子邮件等,支持多种语言。
用途: 生成用于开发、测试、填充数据库的假数据。
优点:
提供丰富的数据类型和多语言支持。
易于使用,有广泛的社区支持。
缺点:
随机性:生成的数据是完全随机的,可能不适合需要具体模式或关联数据的用例。
维护性:虽然库本身维护良好,但可能会有 API 变动的风险。
2. json-server
描述:使用简单的 JSON 文件快速搭建 REST API 的工具。
用途:快速原型开发、小型项目的前端开发和 API 演示、前端开发测试。
优点:
快速设置:极快速地搭建一个具有 REST API 的服务器。
轻量级:无需复杂配置,一个简单的 JSON 文件即可启动,适合小型或个人项目。
灵活性:可以根据需要轻松定制路由和返回数据。
缺点:
不适合大型应用:对于复杂或大规模的后端模拟可能不够强大。
功能限制:没有像真实后端那样的复杂逻辑处理能力。
3. Mirage JS
Mirage JS • An API mocking library for frontend developers
GitHub 仓库: GitHub - miragejs/miragejs: A client-side server to build, test and share your JavaScript app
描述: Mirage JS 是一个在前端应用中模拟后端逻辑的库(前端开发者可以在浏览器中模拟后端 API 的 JavaScript 库。)。它提供了一个富有表现力的 API 来构建出功能完备的模拟后端。
用途:前端应用开发和测试,尤其是在没有后端服务的情况下。
优点:
高度可配置,可以模拟复杂的后端逻辑,包括数据库和关系,支持 GraphQL 和 REST API。
集成到现有前端项目中非常方便。
缺点:
学习曲线较高。
在浏览器中运行复杂模拟可能影响性能。
4. msw (Mock Service Worker)
GitHub 仓库:GitHub - mswjs/msw: Seamless REST/GraphQL API mocking library for browser and Node.js.
描述::MSW 是一个使用 Service Worker 在浏览器层面拦截网络请求来模拟 API 的库。它允许你模拟服务器响应,而不需要更改客户端的代码。MSW 适用于浏览器环境和 Node.js。
用途:开发和测试中拦截和修改 API 请求和响应,特别适用于单元和集成测试。
优点:
提供接近真实环境的 API 拦截,支持 REST 和 GraphQL API 模拟。
支持浏览器和 Node.js 环境。
缺点:
需要理解 Service Workers 的工作原理。
在不支持 Service Workers 的环境中无法使用。
5. Nock
GitHub 仓库:GitHub - nock/nock: HTTP server mocking and expectations library for Node.js
描述: Nock 是一个 Node.js 的 HTTP 服务器模拟和期望库,允许你模拟 HTTP 请求和响应以进行测试,专为测试设计。
用途:在 Node.js 环境中用于单元测试和集成测试中模拟 HTTP 请求。
优点:
强大的请求拦截和响应能力。
非常适合自动化测试环境。
缺点:
仅限于 Node.js,不适用于浏览器。
学习和使用相对复杂。
6. axios-mock-adapter
GitHub: GitHub - ctimmerm/axios-mock-adapter: Axios adapter that allows to easily mock requests
描述:用于模拟 axios 请求和响应的库,便于前端开发和测试。
用途:主要用于单元测试和前端开发中,模拟和测试 HTTP 请求。
优点:
测试隔离:确保测试不依赖外部服务,提高可靠性和速度。
简单集成:与 axios 直接集成,易于设置和使用。
灵活性:可自定义拦截请求和响应,模拟不同的 HTTP 状态码和响应时间。
缺点:
局限性:仅适用于使用 axios 的项目。
功能有限:主要用于简单的响应模拟,不适合复杂后端逻辑模拟。
不适用于生产:设计仅适用于测试环境,不应在生产环境中使用。
每个工具或库都有其特定的优势和最佳应用场景,选择时你可以根据项目需求、开发环境和个人偏好来考虑。
- 感谢你赐予我前进的力量