一、安装
npm install mockjs --save-dev
npm install @types/mockjs --save-dev
二、基本配置
1.创建Mock入口文件(src/mock/index.ts)
import Mock from 'mockjs'
// 配置 Mock
Mock.setup({
timeout: '200-600', // 模拟网络延迟,随机 200-600ms
})
// 引入各个模块的 mock
import './menu'
import './auth'
// import './user'
// import './order'
console.log('[Mock] Mock 服务已启动')
2.在main.ts中引入(仅开发环境)
//src/main.ts
if (import.meta.env.DEV && import.meta.env.VITE_USE_MOCK === 'true') {
import('./mock/index')
}
三、创建Mock数据的标准写法
1.使用Mock.js语法生成随机数据
// src/mock/user.ts
import Mock from 'mockjs'
import type { UserResponse, UserListParams } from '@/api/types'
// 使用 Mock.js 生成随机数据
export const userMockData = Mock.mock({
'list|10-20': [
{
'id|+1': 1,
'name': '@cname', // 随机中文姓名
'email': '@email', // 随机邮箱
'phone': /^1[3-9]\d{9}$/, // 正则表达式生成手机号
'age|18-60': 1, // 18-60 之间的随机数
'avatar': '@image("200x200", "@color", "@name")', // 随机图片
'address': '@county(true)', // 随机地址
'createTime': '@datetime', // 随机日期时间
'status|1': ['active', 'inactive'], // 随机选择
}
],
'total': 100,
})
// Mock 接口
Mock.mock(/\/api\/user\/list/, 'get', (options: any): UserResponse => {
const url = options?.url || ''
const params = new URLSearchParams(url.split('?')[1] || '')
const page = Number(params.get('page')) || 1
const pageSize = Number(params.get('pageSize')) || 10
return {
code: 200,
message: '获取用户列表成功',
data: {
list: userMockData.list.slice((page - 1) * pageSize, page * pageSize),
total: userMockData.total,
page,
pageSize,
},
}
})
2.使用静态数据(推荐用于固定数据)
// src/mock/menu.ts
import Mock from 'mockjs'
import type { MenuItem, MenuResponse } from '@/api/types'
// 静态菜单数据
export const menuMockData: MenuItem[] = [
{
id: 'dashboard',
title: '仪表盘',
path: '/dashboard',
icon: 'TrendCharts',
meta: {
title: '仪表盘',
icon: 'TrendCharts',
},
},
// ... 更多菜单项
]
// Mock 接口
Mock.mock(/\/api\/menu\/list/, 'get', (options: any): MenuResponse => {
return {
code: 200,
message: '获取菜单成功',
data: menuMockData,
}
})
四、常用Mock.js语法
1.基础数据类型
Mock.mock({
// 字符串
'name': '@cname', // 中文姓名
'nameEn': '@name', // 英文姓名
'word': '@word', // 单词
'sentence': '@sentence', // 句子
'paragraph': '@paragraph', // 段落
// 数字
'age|18-60': 1, // 18-60 之间的随机数
'score|1-100': 1, // 1-100 之间的随机数
'price|10.2-100.2': 1, // 10.2-100.2 之间的随机小数(保留2位)
// 布尔值
'isActive|1': true, // 50% 概率为 true
'isVip|1-2': true, // 1/3 概率为 true
// 日期
'date': '@date', // 日期:2023-01-01
'datetime': '@datetime', // 日期时间:2023-01-01 12:00:00
'time': '@time', // 时间:12:00:00
'now': '@now', // 当前时间
// 图片
'avatar': '@image("200x200")', // 200x200 的随机图片
'image': '@image("300x200", "#50B347", "#FFF", "Mock")',
// 颜色
'color': '@color', // 随机颜色
'hex': '@hex', // 十六进制颜色
// 其他
'url': '@url', // 随机 URL
'email': '@email', // 随机邮箱
'ip': '@ip', // 随机 IP
'id': '@id', // 随机 ID
'guid': '@guid', // GUID
})
2.数组生成
Mock.mock({
// 生成 1-10 个元素的数组
'list|1-10': [
{
'id|+1': 1, // 自增,从 1 开始
'name': '@cname',
}
],
// 生成固定数量的数组
'items|5': [
{
'id|+1': 1,
'name': '@word',
}
],
})
五.完整的Mock文件
// src/mock/order.ts
import Mock from 'mockjs'
import type { OrderResponse, OrderListParams } from '@/api/types'
// 订单状态枚举
const orderStatus = ['pending', 'paid', 'shipped', 'completed', 'cancelled']
// 生成订单列表数据
const generateOrderList = (count: number = 10) => {
return Mock.mock({
[`list|${count}`]: [
{
'id|+1': 1000,
'orderNo': '@id', // 随机订单号
'userId|1-100': 1,
'userName': '@cname',
'amount|100-10000.2': 1, // 100-10000 之间的金额,保留2位小数
'status|1': orderStatus,
'createTime': '@datetime',
'payTime': '@datetime',
'items|1-5': [
{
'productId|+1': 1,
'productName': '@ctitle(5,10)', // 5-10 个字的标题
'quantity|1-10': 1,
'price|10-1000.2': 1,
}
],
}
],
}).list
}
// GET 请求:获取订单列表
Mock.mock(/\/api\/order\/list/, 'get', (options: any): OrderResponse => {
const url = options?.url || ''
const params = new URLSearchParams(url.split('?')[1] || '')
const page = Number(params.get('page')) || 1
const pageSize = Number(params.get('pageSize')) || 10
const status = params.get('status') || ''
// 生成数据
let list = generateOrderList(50) // 生成 50 条数据
// 根据状态过滤
if (status) {
list = list.filter((item: any) => item.status === status)
}
// 分页
const start = (page - 1) * pageSize
const end = start + pageSize
const pageList = list.slice(start, end)
return {
code: 200,
message: '获取订单列表成功',
data: {
list: pageList,
total: list.length,
page,
pageSize,
},
}
})
// POST 请求:创建订单
Mock.mock(/\/api\/order\/create/, 'post', (options: any) => {
const body = typeof options.body === 'string'
? JSON.parse(options.body)
: options.body
const newOrder = Mock.mock({
id: '@id',
orderNo: '@id',
userId: body.userId,
amount: body.amount,
status: 'pending',
createTime: '@now',
items: body.items,
})
return {
code: 200,
message: '创建订单成功',
data: newOrder,
}
})
// GET 请求:获取订单详情
Mock.mock(/\/api\/order\/detail/, 'get', (options: any) => {
const url = options?.url || ''
const orderId = url.split('/').pop() || ''
const order = Mock.mock({
id: orderId,
orderNo: '@id',
userId: '@id',
userName: '@cname',
amount: '@float(100, 10000, 2, 2)',
status: 'paid',
createTime: '@datetime',
payTime: '@datetime',
address: '@county(true)',
items: [
{
productId: 1,
productName: '@ctitle',
quantity: 2,
price: 99.99,
}
],
})
return {
code: 200,
message: '获取订单详情成功',
data: order,
}
})
六、类型安全的Mock写法
// src/mock/types.ts
export interface MockResponse<T = any> {
code: number
message: string
data: T
}
// src/mock/user.ts
import Mock from 'mockjs'
import type { User, UserListResponse } from '@/api/types'
import type { MockResponse } from './types'
// 类型安全的 Mock 函数
const createMockResponse = <T>(
data: T,
message: string = '操作成功'
): MockResponse<T> => {
return {
code: 200,
message,
data,
}
}
// 使用
Mock.mock(/\/api\/user\/list/, 'get', (): MockResponse<UserListResponse> => {
const list = generateUserList(20)
return createMockResponse({
list,
total: list.length,
}, '获取用户列表成功')
})
七、最佳实践
1.统一响应式格式
// src/mock/utils.ts
export const createSuccessResponse = <T>(
data: T,
message: string = '操作成功'
) => ({
code: 200,
message,
data,
})
export const createErrorResponse = (
message: string = '操作失败',
code: number = 500
) => ({
code,
message,
data: null,
})
2.统一使用
import { createSuccessResponse, createErrorResponse } from './utils'
Mock.mock(/\/api\/user\/list/, 'get', () => {
return createSuccessResponse(userList, '获取用户列表成功')
})
Mock.mock(/\/api\/user\/create/, 'post', (options) => {
// 验证逻辑
if (!options.body) {
return createErrorResponse('参数错误', 400)
}
return createSuccessResponse(newUser, '创建用户成功')
})
3.环境控制
// src/mock/index.ts
if (import.meta.env.DEV && import.meta.env.VITE_USE_MOCK === 'true') {
// 只在开发环境且启用 mock 时加载
import('./menu')
import('./auth')
}
当你决定不再使用Mock数据,而是直接调用真实的后端接口提供数据,核心思想就是:移除或禁用Mock,直接用fetch/axios调真实API。
1.停止使用Mock.js
import './mock' // ← 删除或注释掉这行,这样的话所有请求都会走真实网络。
2.条件引入(推荐保留单仅开发使用) 后续还想mock做其他功能,可以加环境判断。
// main.js
if (import.meta.env.DEV) {
// 仅在开发环境加载 mock(可选)
// import('./mock')
}
如果确定要用真实接口,就不要引入mock数据。
3.在组件中直接调用真实接口
// ❌ 旧方式(依赖 mock 拦截 /api/chart)
const res = await fetch('/api/chart-data')
有真实的后端接口比如
https://your-backend.com/api/v1/sales-report
然后vue3.0组件中 使用fetxh(原生无需安装)
<script setup>
import { onMounted, ref } from 'vue'
import * as echarts from 'echarts'
const chartRef = ref(null)
const loading = ref(true)
onMounted(async () => { try { // ✅ 调用真实接口
const response = await fetch('https://your-backend.com/api/v1/sales-report') if (!response.ok) throw new Error('请求失败')
const data = await response.json()
// 初始化 ECharts
const chart = echarts.init(chartRef.value)
chart.setOption({
title: { text: '销售报表' },
xAxis: { data: data.categories },
yAxis: {},
series: [{ type: 'bar', data: data.values }]
})
} catch (error) {
console.error('获取图表数据失败:', error)
} finally {
loading.value = false
}
})
</script>
<template>
<div v-if="loading">加载中...</div>
<div ref="chartRef" style="width: 600px; height: 400px;"></div>
</template>
或者使用axios(更加强大,支持拦截器,自动JSON)
1.安装
npm install axios
import axios from 'axios'
const { data } = await axios.get('https://your-backend.com/api/v1/sales-report') // 直接使用 data
处理跨域问题(如果前后端域名不用)
如果你的前端是 http://localhost:5173,而后端是 https://api.yourcompany.com,浏览器会因 CORS(跨域) 拦截请求。
解决方案
后端设置CORS头 后端需返回:
Access-Control-Allow-Origin: http://localhost:5173 // 或 *
开发阶段用Vite代理(临时方案) vite.config.js配置代理,避免跨域:
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'https://your-backend.com',
changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '/api/v1')
}
}
}
})
然后前端请求写成
fetch('/api/sales-report') // 实际转发到 https://your-backend.com/api/v1/sales-report
四、移除mock.js 如果确定不再用Mock,直接删除mock/目录和相关文件。让项目更干净。