Vue3 + TypeScript 项目中使用 Mock 数据指南
背景
产品:这里有个需求,计划月底上线,你们评估下开发时间,保证月底能上线现网。
测试:我需要一周的测试时间,包括功能测试、性能测试、兼容性测试等。
UI:我需要一周时间,包括页面布局、交互设计、颜色方案等。
后端:我需要两周时间,包括数据库设计、接口开发、业务逻辑实现等。
前端:我走?
产品:你想想办法。
前端:我可以牺牲自己的开发时间,通过接口mock来并行开发,需要后端提前提供接口文档,我同步进行页面开发和逻辑实现。
为了需求正常上线,无私的前端又为自己找了个加班的机会。
前言
在前端开发过程中,我们经常会遇到后端接口尚未完成,但前端需要提前开发页面和功能的情况。 这时,使用 Mock 数据就成为了一种非常有效的解决方案。 本文将介绍如何在 Vue3 + TypeScript 项目中搭建和使用 Mock 数据。
什么是 Mock 数据
概念
Mock 数据是指在开发过程中,为了模拟后端接口返回的数据,而创建的虚假数据。
作用
-
并行开发:前端可以与后端同时开发,不需要等待后端接口完成
-
独立测试:可以模拟各种边界情况和错误场景
-
性能测试:可以模拟大量数据,测试前端性能
-
演示效果:在没有后端服务的情况下,也能展示完整的功能
优势
-
提高开发效率:减少等待后端接口的时间
-
增强代码健壮性:可以测试各种异常情况
-
改善团队协作:明确接口规范,减少沟通成本
-
简化测试流程:可以快速模拟各种场景
环境搭建
安装依赖
在 Vue3 + TypeScript 项目中,需要安装以下依赖:
bash
# 安装 mockjs 库
npm install mockjs --save-dev
# 安装 vite-plugin-mock 插件
npm install vite-plugin-mock --save-dev
# 安装 @types/mockjs 类型定义(可选但推荐)
npm install --save-dev @types/mockjs
配置 Vite
在 vite.config.ts 文件中配置 vite-plugin-mock 插件:
typescript
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
import { viteMockServe } from "vite-plugin-mock";
export default defineConfig({
plugins: [
vue(),
viteMockServe({
// mock 文件存放路径
mockPath: "./mock",
// 启用 mock 功能
enable: true,
// 显示请求日志
logger: true,
}),
],
resolve: {
alias: {
"@": resolve(__dirname, "./src"),
},
},
});
配置 TypeScript
在 tsconfig.app.json 文件中配置路径别名,确保 TypeScript 能够正确解析 @/ 路径:
json
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
},
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}
配置 Mock 数据
快速开始 - 最简单的用例
模拟第一个简单接口
第一步:创建最简单的 Mock 接口
在 mock 文件夹下创建一个简单的 hello.ts 文件:
typescript
// mock/hello.ts
import { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/api/hello",
method: "get",
response: () => {
return {
code: 200,
message: "success",
data: "Hello, Mock!",
};
},
},
] as MockMethod[];
第二步:在组件中调用
vue
<template>
<div>
<h2>{{ message }}</h2>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import axios from "axios";
const message = ref("");
onMounted(async () => {
try {
const response = await axios.get("/api/hello");
message.value = response.data.data;
} catch (error) {
console.error("请求失败:", error);
}
});
</script>
运行结果:页面显示 "Hello, Mock!"
中级用例 - 简单数据列表
这个用例展示如何返回一个简单的数据列表。
创建 Mock 接口
在 mock 文件夹下创建 products.ts 文件:
typescript
// mock/products.ts
import { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/api/products",
method: "get",
response: () => {
return {
code: 200,
message: "success",
data: [
{ id: 1, name: "商品1", price: 99 },
{ id: 2, name: "商品2", price: 199 },
{ id: 3, name: "商品3", price: 299 },
],
};
},
},
] as MockMethod[];
在组件中调用
vue
<template>
<div>
<h2>商品列表</h2>
<ul>
<li v-for="product in products" :key="product.id">
{{ product.name }} - ¥{{ product.price }}
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import axios from "axios";
interface Product {
id: number;
name: string;
price: number;
}
const products = ref<Product[]>([]);
onMounted(async () => {
try {
const response = await axios.get("/api/products");
products.value = response.data.data;
} catch (error) {
console.error("获取商品列表失败:", error);
}
});
</script>
运行结果:页面显示商品列表,包含3个商品的信息。
进阶用例 - 用户数据管理
接下来,我们创建一个更完整的贴合业务场景的用例。
创建 Mock 文件
创建一个 user.ts 文件来模拟用户相关的接口:
typescript
// mock/user.ts
import { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/api/user/list", // 接口路径
method: "get", // 请求方法
response: ({ query }: { query: Record<string, string> }) => {
// 模拟分页数据
const page = parseInt(query.page) || 1;
const limit = parseInt(query.limit) || 10;
const total = 100;
// 生成模拟数据
const list = [];
for (let i = 0; i < limit; i++) {
const index = (page - 1) * limit + i;
if (index < total) {
list.push({
id: index + 1,
name: `用户${index + 1}`,
age: Math.floor(Math.random() * 30) + 18,
email: `user${index + 1}@example.com`,
createdAt: new Date().toISOString(),
});
}
}
return {
code: 200,
message: "success",
data: {
list,
total,
page,
limit,
},
};
},
},
{
url: "/api/user/detail",
method: "get",
response: ({ query }: { query: Record<string, string> }) => {
const id = query.id;
return {
code: 200,
message: "success",
data: {
id,
name: `用户${id}`,
age: Math.floor(Math.random() * 30) + 18,
email: `user${id}@example.com`,
createdAt: new Date().toISOString(),
address: "北京市朝阳区",
phone: "13800138000",
},
};
},
},
{
url: "/api/user/create",
method: "post",
response: ({ body }: { body: Record<string, any> }) => {
return {
code: 200,
message: "success",
data: {
id: Math.floor(Math.random() * 10000),
...body,
},
};
},
},
] as MockMethod[];
调用 Mock 数据
mock数据的调用使用 axios 实现,本文暂不做过多覆盖。
创建 API 服务
在 src/api 目录下创建 user.ts 文件,定义 API 调用函数:
typescript
// src/api/user.ts
import axios from "axios";
/**
* 获取用户列表
* @param params 分页参数
* @returns Promise 响应数据
*/
export const getUserList = (params: { page: number; limit: number }) => {
return axios.get("/api/user/list", { params });
};
/**
* 获取用户详情
* @param id 用户ID
* @returns Promise 响应数据
*/
export const getUserDetail = (id: number) => {
return axios.get("/api/user/detail", { params: { id } });
};
/**
* 创建用户
* @param data 用户数据
* @returns Promise 响应数据
*/
export const createUser = (data: {
name: string;
age: number;
email: string;
}) => {
return axios.post("/api/user/create", data);
};
在组件中使用
在 Vue 组件中使用 API 服务调用 Mock 数据:
vue
<template>
<div class="user-list">
<h2>用户列表</h2>
<div v-if="loading">加载中...</div>
<div v-else>
<ul>
<li v-for="user in userList" :key="user.id">
{{ user.name }} - {{ user.age }}岁 - {{ user.email }}
</li>
</ul>
<div class="pagination">
<button @click="changePage(1)" :disabled="currentPage === 1">
首页
</button>
<button
@click="changePage(currentPage - 1)"
:disabled="currentPage === 1"
>
上一页
</button>
<span>第 {{ currentPage }} 页,共 {{ totalPages }} 页</span>
<button
@click="changePage(currentPage + 1)"
:disabled="currentPage === totalPages"
>
下一页
</button>
<button
@click="changePage(totalPages)"
:disabled="currentPage === totalPages"
>
末页
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { getUserList } from "@/api/user";
// 响应式数据
const userList = ref<any[]>([]);
const loading = ref(false);
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
// 计算属性
const totalPages = computed(() => {
return Math.ceil(total.value / pageSize.value);
});
/**
* 获取用户列表数据
*/
const fetchUserList = async () => {
loading.value = true;
try {
const response = await getUserList({
page: currentPage.value,
limit: pageSize.value,
});
userList.value = response.data.data.list;
total.value = response.data.data.total;
} catch (error) {
console.error("获取用户列表失败:", error);
} finally {
loading.value = false;
}
};
/**
* 切换页码
* @param page 页码
*/
const changePage = (page: number) => {
currentPage.value = page;
fetchUserList();
};
// 组件挂载时获取数据
onMounted(() => {
fetchUserList();
});
</script>
常见用例和最佳实践
常见用例
-
分页数据:模拟带分页的列表数据
-
详情数据:模拟单个资源的详细信息
-
表单提交:模拟创建、更新操作
-
错误场景:模拟各种错误状态码和错误信息
-
文件上传:模拟文件上传接口
最佳实践
-
目录结构清晰:按模块组织 mock 文件
-
数据结构一致:与后端接口保持一致的数据结构
-
模拟真实场景:包括正常、异常、边界等各种场景
-
使用 TypeScript:为 mock 数据添加类型定义
-
注释完善:为复杂的 mock 逻辑添加注释
-
定期更新:根据后端接口变化及时更新 mock 数据
故障排除提示
- mock 数据不生效
-
检查
vite.config.ts中的mockPath配置是否正确 -
检查 mock 文件是否在正确的目录下
-
检查接口路径是否匹配
- TypeScript 类型错误
-
确保安装了
@types/mockjs类型定义 -
为 mock 数据添加正确的类型注解
- 生产环境泄露
- 确保在生产环境中禁用 mock 功能
- 性能问题
-
避免在 mock 函数中执行复杂的计算
-
对于大量数据,考虑使用分页或虚拟滚动
常见问题
1. 路径别名问题
问题:找不到模块 "@/api/user" 或其相应的类型声明。
原因 :虽然在 vite.config.ts 中配置了路径别名,但在 tsconfig.app.json 中没有配置相应的 paths。
解决方案 :在 tsconfig.app.json 中添加 paths 配置:
json
{
"compilerOptions": {
// ... 其他配置
"paths": {
"@/*": ["./src/*"]
}
}
}
2. 接口实现不完整
问题:调用某个 API 函数时返回 404 错误。
原因:在 mock 文件中没有实现对应的接口。
解决方案:确保所有 API 调用都有对应的 mock 接口实现。
3. 类型定义缺失
问题:使用 mockjs 时缺少类型定义。
原因 :没有安装 @types/mockjs 类型定义文件。
解决方案:安装类型定义文件:
bash
npm install --save-dev @types/mockjs
替代方案比较
Mock.js vs JSON Server
-
Mock.js:专注于数据模拟,功能强大,支持各种数据类型和随机数据生成
-
JSON Server:快速创建 RESTful API,基于 JSON 文件,适合简单场景
Mock.js vs MSW (Mock Service Worker)
-
Mock.js:在构建工具层面拦截请求,配置简单
-
MSW:在浏览器层面拦截请求,支持 Service Worker,更接近真实网络请求
Mock.js vs 手写本地存储
-
Mock.js:功能完整,支持各种 HTTP 方法和场景
-
手写本地存储:简单直接,适合非常简单的场景
注意事项
-
环境隔离:确保 mock 功能只在开发和测试环境启用
-
数据安全:不要在 mock 数据中使用真实的敏感信息
-
接口一致性:与后端保持接口规范一致,避免后期大量修改
-
代码管理:将 mock 相关代码与业务代码分离,便于维护
-
性能考虑:避免生成过多数据,影响前端性能
-
测试覆盖:确保真实接口对接后,进行完整的回归测试
总结
Mock 数据是前端开发中的重要工具,它可以帮助我们提高开发效率,增强代码健壮性,改善团队协作。
「九九八十一难,难难皆是修行」