摘要
众所周知,现在的前后端开发都是独立的,除了一些老项目。但是如果公司的开发流程不规范就可能出现前端开发的阻塞,或者出现得多做一些无用功。正确的开发流程应该是:需求评审--需求确认--后端接口设计并输出文档 -- 前/后端开发 -- 联调 -- 测试 -- 上线 。这里主要强调优先输出接口设计文档的重要性。
Mock 数据
mock数据的作用是让前端开发不依赖后端的开发进度,减少创建数据的时间,减少联调的时间。但是mock也有自己的局限,对于一些复杂的接口没法很好的兼容,对于下载文件也不太好mock等。下面用 vue3 + vite 举例
安装依赖
npm install vite-plugin-mock -D
配置
在
src
目录的同级上新建mock文件夹;并在vite.config.js
的plugins
中添加下面配置,联调时将选项中的enable
设置为false
。
javascript
// mock/index.js -- 按模块导入方便管理
import user from './user'
import data from './data'
export default [...user, ...data]
// vite.config.js
viteMockServe({
mockPath: path.resolve(__dirname, '../../mock'),
// enable: false,
localEnabled: viteEnv.VITE_APP_ENV === 'development',
watchFiles: true,
})
如何Mock数据
如何使用的官方文档:
vite-plugin-mock配置中文文档
mock数据如何使用下面写一些常用的写法,以及对于
Restful Api
该如何通过mock
的接口拦截;其他的使用请看文档。说明一下
Restful Api
类型的接口:删除:
/api/v1/project/:id
请求方法为:Delete
修改:
/api/v1/project/:id
请求方法为:Post
详情:
/api/v1/project/:id
请求方法为:Get
某个项目里的其他列表:
/api/v1/project/:id/other/list
请求方法为:Get
第一种:非 Restful Api
javascript
[
{
url: '/dev-api/api/v1/project',
method: 'get',
response: () => {
return Mock.mock({
code: 0,
msg: 'OK',
'data|10': [
{
id: '@guid',
name: '@string',
desc: '@sentence',
created_at: '@integer(1693904305000, 1725526705000)',
},
],
})
},
},
// 有查询参数,以下所有都是通用的
{
url: '/dev-api/api/v1/project/type/list',
method: 'get',
response: ({ query }) => {
const { ... } = query
let list = ['default']
// 根据条件生成list
return {
code: 0,
msg: 'OK',
data: {
list,
total: 2,
},
}
},
},
]
第二种: Restful Api
:/api/v1/project/:id
,接口参数在后面
javascript
[
{
url: /\/dev-api\/api\/v1\/project\/*/,
method: 'delete',
response: () => {
return {
code: 0,
msg: 'OK',
data: null,
}
},
},
]
第三种: Restful Api
:/api/v1/project/:id/other/list
,接口参数在中间
javascript
{
url: /\/dev-api\/api\/v1\/project\/[^/]+\/other\/list/,
method: 'get',
response: () => {
return {
code: 0,
msg: 'OK',
data: Mock.mock({
id: '@guid',
name: '@string',
}),
}
},
}
接口字段映射
在我们写表单,写表格时都会绑定一个
prop
属性的值,该值对应的就是后端接口返回的字段名
;传参数时也是后端需要什么前端传什么,如果后端需要的时下划线的参数project_name
,安装前端的代码习惯都是驼峰命名
的参数名,这时候你可以将驼峰转下划线。这里说一下更好的实践,那就是这一节的主题:接口字段的映射。将后端接口的响应数据,传给后端的请求参数,通过字段映射转换成前端需要的字段名和后端需要的参数名。
实现
在
src
中新建field-map
文件夹,按模块新增对应的文件,比如project.js
。下面是具体代码
javascript
import { mapRequestFields, formatDate } from '@/utils/common'
export const fieldMap = {
name: 'name',
description: 'description',
creator: 'creator',
createdAt: 'created_at',
}
// Format project list
export function formatList(data) {
return (
data?.map(item => ({
id: item.id,
name: item.name,
description: item.description,
creator: item.creator,
createdAt: formatDate(item.created_at),
})) || []
)
}
export function formatQuery(params) {
return mapRequestFields(params, fieldMap)
}
对象类型字段转换的翻转
如果需要将后端的响应对象转换成前端需要的字段名,或者在表格排序时需要将字段转换回去,可以通过下面的方式实现。其他更多的需求可以自己拓展
javascript
export const fieldMapReverse = Object.keys(fieldMap).reduce((acc, key) => {
acc[fieldMap[key]] = key
return acc
}, {})
export function formatQuery(params) {
return mapRequestFields(params, fieldMapReverse )
}
mapRequestFields的实现,对请求参数进行转换
javascript
// 未实现嵌套的转换
export function mapRequestFields(obj, map) {
const isFormData = obj instanceof FormData
const mapFields = isFormData ? new FormData() : {}
if (isFormData) {
for (const [key, value] of obj.entries()) {
if (value === 'undefined' || value === null || value === '') return
const newKey = map[key] || key
mapFields.append(newKey, value)
}
} else {
Object.keys(obj).forEach(key => {
if (obj[key] === 'undefined' || obj[key] === null || obj[key] === '') return
const newKey = map[key] || key
mapFields[newKey] = obj[key]
})
}
return mapFields
}