核心是通过接口抽象、构造注入和工厂函数实现依赖解耦,业务逻辑不感知底层实现,mock与真实服务可零修改切换。

核心在于把“谁创建依赖”这件事从代码内部移出去,让业务逻辑只关心“怎么用”,不关心“从哪来”。只要接口一致,Mock 和真实服务就能无缝替换,不用改一行业务代码。
把硬编码的请求调用改成可注入参数
别在组件或 Hook 里直接写 fetch('/api/user') 或 axios.get('/api/order')。这类写法绑死了实现,无法拦截、无法替换。
- 改成函数参数传入:例如
useUser(requestFn = fetch),测试时传mockFetch,生产环境保持默认 - 若用 axios,同样适用:
useUser(axios.get)或useUser(apiClient.getUser) - 关键不是封装工具函数,而是让业务逻辑彻底不感知底层是 fetch、axios 还是 Mock 函数
用工厂函数统一管理服务实例
避免到处写 new ApiClient() 或 new Logger()——这等于把实现细节散落在各处,一换就要全局搜索替换。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
- 新建
services.ts,集中导出工厂函数:export const createApiClient = (options: { baseUrl: string }) => new ApiClient(options) - 在应用入口一次性创建并组装:
const services = { api: createApiClient({ baseUrl: import.meta.env.VITE_API_URL }) } - 所有业务模块都从这个
services对象取实例,而不是自己 new - Mock 场景下,只需让
createApiClient返回 mock 实例,其余代码完全不动
接口抽象 + 构造注入,才是 Mock 可行的前提
没有统一契约,Mock 就只是随便写的假函数,没法替代真实行为。
- 先定义接口:
interface UserProvider { get(id: number): Promise<user> }</user> - 真实实现和 Mock 实现都严格遵守该接口,比如
class HttpUserProvider implements UserProvider和class MockUserProvider implements UserProvider - 业务类通过构造函数接收该接口:
constructor(private userProvider: UserProvider) - 测试时传
new MockUserProvider(),生产环境传new HttpUserProvider(),零修改
切换控制交给构建或运行时配置
最终用哪个实现,不应写死在业务逻辑里,而应由启动方式决定。
- 通过环境变量控制:
import.meta.env.VITE_USE_MOCK === 'true'时加载 Mock 工厂 - 在入口文件中做一次判断和组装,例如:
const services = useMock ? mockServices() : realServices() - 也可以配合打包工具,在构建阶段剔除 Mock 模块(如 Vite 的
define或 Webpack 的DefinePlugin) - 所有业务代码只依赖
services,不感知具体是哪套实现
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










