在现在习惯的开发流程中,特别是快速交付流程里面,我们通常会在开始动工之前通过约定好 API 接口,然后前端通过使用 Mock 数据在本地模拟出 API 返回的正确的数据结构,完成全部的前端逻辑开发,然后在项目上线前修改请求路径到后端,如果双方都严格按照最开始的约定进行,并且在此期间没有任何的业务流程修改的话,那前端可能只需要简单的请求路径,就可以完成前后端连调工作。
在上一节课的练习中,我们采用了更原始的方法,直接在代码中写死数据,还要是一个列表,我们可以通过循环的方式来取巧生成。但是如果是一个对象,并且是一个大对象的话,那我们要么都用“11111”来渲染我们的整个页面,要么就要花大量的时间去编写“假数据”。
Umi 提供了开箱即用的 Mock 功能,能够用方便简单的方式来完成 Mock 数据的设置。
Mock 约定目录
Umi 约定 /mock
目录下的所有文件为 Mock 文件
,每一个 mock 文件都会返回一个 default 对象,例如这样的目录结构:
. ├── mock ├── todos.ts ├── items.ts └── users.ts └── src └── pages └── index.tsx 复制代码
则 /mock
目录中的 todos.ts
, items.ts
和 users.ts
就会被 Umi 视为 Mock 文件
来处理。
值得注意的是 mock 目录下的文件的文件名对真正的 mock 服务不会产生任何的影响,所以你可以仅仅从业务的分类的角度来组织他们,甚至你讲所有的 mock 服务放在同一个文件中存放也可以。
Mock 文件
Mock 文件默认导出一个对象,而对象的每个 Key 对应了一个 Mock 接口,值则是这个接口所对应的返回数据,例如这样的 Mock 文件:
// ./mock/users.ts export default { // 返回值可以是数组形式 'GET /api/users': [ { id: 1, name: 'foo' }, { id: 2, name: 'bar' } ], // 返回值也可以是对象形式 'GET /api/users/1': { id: 1, name: 'foo' }, } 复制代码
就声明了两个 Mock 接口,透过 GET /api/users
可以拿到一个带有两个用户数据的数组,通过 GET /api/users/1
可以拿到某个用户的模拟数据。
请求方式
当 Http 的请求方式是 GET 时,可以省略方法部分,只需要路径即可,例如:
// ./mock/users.ts export default { '/api/users': [ { id: 1, name: 'foo' }, { id: 2, name: 'bar' } ], '/api/users/1': { id: 1, name: 'foo' }, } 复制代码
也可以用不同的请求方法,例如 POST
,PUT
,DELETE
:
// ./mock/users.ts export default { 'POST /api/users': { result: 'true' }, 'PUT /api/users/1': { id: 1, name: 'new-foo' }, } 复制代码
关闭 Mock
Umi 默认开启 Mock 功能,如果不需要的话可以从配置文件关闭:
// .umirc.ts export default { mock: false, }; 复制代码
或是用环境变量的方式关闭:
MOCK=none umi dev 复制代码
以上的内容大部分你可以在官网中找到,以下的内容是开发中的一些小 tip。如果你看到这个文章的时间较晚,那可能也能在官网中看到,因为这个系列的所有文档,后面会尽量整理到官网的内容中。
取到请求的参数
其实 Umi 中提供的 Mock 能力,本质上是一个 express 的中间件,你可以通过 req 取到请求的入参和 header 等信息。
import { Request, Response } from 'express'; export default { 'POST /api/list': (req: Request, res: Response) => { const { body } = req; const { pageSize, offset } = body; // 从这里取出 pageSize, offset return res.json({ success:true }); }, } 复制代码
引入 Mock.js
上节课中我们手写了一个数据,有时候很尴尬的是取名困难,要让数据看起来好看一点,就要让数据重复的更少。
{ id: i, title: "卡片列表", description: "Umi@4 实战教程,专门针对中后台项目零基础的朋友,不管你是前端还是后端,看完这个系列你也有能力合理“抗雷”,“顶坑”", } 复制代码
这时候我们可以引入一些现在流行的 Mock 数据的生成工具,比如 Mock.js ,来帮我们方便的生成随机的模拟数据,会让我们的模拟数据看起来更加真实。
类似上节课的练习数据,我们可以这么写。
import mockjs from "mockjs"; export default { "GET /api/list": mockjs.mock({ "data|10": [{ id: "@id", title: "@name", description: "@cparagraph(2)" }], }), }; 复制代码
会自动生成类似如下数据,太长了,我这里摘录了两段,实际上生成了 10 个数据,这是通过 data|10
来指定的,你在表格数据中,可以给一个比较大的值来渲染一个超长列表。
{ "data": [ { "id": "810000197712245720", "title": "David Lewis", "description": "理史率能厂响命热么克积深先片。每号公状志山织声具接度通满被准。" }, { "id": "230000199101266590", "title": "Sharon White", "description": "是石来验关且公决器重调受白设。农队战社五点团持老了取装场。" } ] } 复制代码
实战
在上节课的技术上我们继续今天的实战。如果你不是每节课都看的朋友,你可以下载上节课的 源码归档
安装依赖
pnpm i mockjs @alita/plugins 复制代码
安装类型包
pnpm i @types/mockjs --D 复制代码
因为今天 Umi@4 正式发布,所以我们同步升级到 Umi@4
修改 packages.json 文件
- "@umijs/plugins": "4.0.0-rc.20", + "@umijs/plugins": "4.0.0", - "umi": "4.0.0-rc.20" + "umi": "4.0.0" 复制代码
修改后,重新执行 pnpm i
。
新建 Mock 文件
新建 mock/list.ts
,并写入如下内容:
import mockjs from "mockjs"; export default { "GET /api/list": mockjs.mock({ success: true, "data|10": [ { id: "@id", title: "@name", description: "@cparagraph(2)", }, ], }), }; 复制代码
引入请求
详细内容在 14 课中已讲解,这里直接写使用。
修改配置文件 config/config.ts
import { defineConfig } from "umi"; export default defineConfig({ // 最终值在插件中设置,所以这里不用写 // title: "Hello Umi", plugins: [ require.resolve("@umijs/plugins/dist/model"), require.resolve("@umijs/plugins/dist/antd"), + require.resolve("@alita/plugins/dist/request"), ], model: {}, + request: {}, antd: {}, }); 复制代码
在 src/pages/listcard/index.tsx
中引入请求,通过日志查看数据结构
import { useRequest, request } from "umi"; // 文件中原有内容略 const ListCard = () => { const { data } = useRequest(() => request("/api/list")); console.log(data); return ( ); }; export default ListCard; 复制代码
{ "data":[] } 复制代码
修改原有的代码将 dataSource={[{}, ...data?.data]}
data
作为 List
的 dataSource
。