在前后端分离的开发中,经常会遇到这样的情形。
需求评估通过,设计图出来了。前端根据设计图和需求,完成了静态页面的展示和mock数据。过了一段时间后,后端把这个需求的接口写好了。前端调用时,发现返回的数据结构和自己mock的数据不一致。
这可能是前后端思考的角度不同导致的。
比如,前端展示时所需要的数据结构如下:
{
name:'xx',
age:15,
like:'pkay',
bastFriends:[
{
name:
}
]
}
而后端返回来的,是这样的
{
name:'xx',
age:15,
like:'play',
list:[
{
name:...
}
]
}
不算太糟,对吧,只是key不一致的情况,我们可以直接
item.bastFriends = item.list
但如果是十分复杂的嵌套情形。
{
...
arr1:[
{
inner_arr:[
{...}
]
},{...}
]
}
就需要一些思考了。
这是前端展示的数据结构:
{
id:1
name:"志愿表1",
rank:10000,
range:3000,
subject:化学,技术,历史,
school_info:[
{//第一个大学
sname:'中央民族大学',
rank:7772,
mark_line:653,
section:1,
professional:[
//该大学下填报的志愿
{ //第一个志愿
id:706,
subject_require:历史,
major_code:017,
major_cat:民族学,
plan_num:2,
line:653,
rank:7772,
year:2020,
section:1,
},{
//第二个志愿
id:649,
subject_require: "无",
major_code: "016",
major_cat: "汉语言文学",
plan_num: 2,
line:654,
rank: 7391,
year: 2020,
section: 1,
}
]
},{//第二个大学
....
}
]
}
这是后端返回的数据结构:
{
id: 1,
name: "志愿表1",
query_param: {"rank":"10000","range":"3000","subject":"\u5316\u5b66,\u6280\u672f,\u5386\u53f2"},
list: [
{
//第一个志愿,没有以大学为单位区分
id:43,
list_id:12,
markline_id:706
markline:[
{
id:706,
line:653,
major_cat: "民族学",
major_code: "017",
plan_num: 2,
rank: 7772,
school_id: 10,
school_name: "中央民族大学",
section: 1,
subject_require: "历史",
year: 2020,
}
]
},{
//第二个志愿
id:44,
list_id:13,
markline_id:649
markline:[
{
id:649,
line:654,
major_cat: "汉语言文学",
major_code: "016",
plan_num: 2,
rank: 7391,
school_id: 10,
school_name: "中央民族大学",
section: 1,
subject_require: "无",
year: 2020,
}
]
},{
//第三个志愿,是其他学校的
}
]
}
莫慌,一切都有迹可循。
思考这样一个问题:需要展示的数据从哪里获取?
1.需要把rank,range,subject从query_param里解析出来。这个不难 ,考虑到测试数据可能不规范,设置了默认值。
let {rank,range,subject} = JSON.parse(data.query_param)||{rank:100,range:1000,subject:'无'}
2.需要将list中的数据按学校分组,庆幸的是有学校id可以作为分组依据。期望分组后得到的数据结构如下:
let obj = {'10':[
{
//第一个志愿,现在以大学id为单位区分
id:43,
list_id:12,
markline_id:706
markline:[
{
id:706,
line:653,
major_cat: "民族学",
major_code: "017",
plan_num: 2,
rank: 7772,
school_id: 10,
school_name: "中央民族大学",
section: 1,
subject_require: "历史",
year: 2020,
}
]
},{
//第二个志愿
id:44,
list_id:13,
markline_id:649
markline:[
{
id:649,
line:654,
major_cat: "汉语言文学",
major_code: "016",
plan_num: 2,
rank: 7391,
school_id: 10,
school_name: "中央民族大学",
section: 1,
subject_require: "无",
year: 2020,
}
]
}
],
'11':[{
//第三个志愿
}]
}
[].reduce可以做到这一点。参考MDN的例子。
let appligroupBySchool = arr.reduce((acc,obj)=>{
let key = obj.markline.school_id
if(!acc[key]){
acc[key] = []
}
acc[key].push(obj)
return acc
},{})
再观察一下前端的数据结构。
shchool_info下第一层的数据:sname,rank,mark_line,section。都可以从第二层的数据markline中获取。
- 其中,rank和mark_line需要遍历一边markline找出最小值,而sname和section可以直接从markline[0]中获取。
- 而professional需要遍历一次分组,获取每组下markline的值,并保存成数组。
for(prop in obj)可以遍历对象。obj['10']就是分组后的其中一组。 [].sort(func)可以找出最小值。 于是,我们可以在遍历对象的循环内,做这样的操作:
let school_info_item = {}
let arr = obj[prop]
let markLine = []
arr.forEach(item=>{
//获取每组下markline的值,并保存成数组
item.markline.m_id = item.id
markLine.push(item.markline)
})
//升序排序下数组
markLine = markLine.sort(compare('line','up'))
//获取需要的数据
infoItem.sname = markLine[0].school_name
infoItem.rank = markLine[0].rank
infoItem.mark_line = markLine[0].line
infoItem.section = markLine[0].section
infoItem.professional = markLine
至此为止,从接口获取的数据就转换成了前端展示所需的数据。增加了一些属性保证显示正确,这样肯定会造成属性冗余。 我的想法是,如果数据只需要用来展示,不做任何增删改的操作,可以把冗余的属性用 delete 属性名 给删掉。
还有一些地方需要注意:增删改操作,需要调用接口时,要根据接口参数,做数据转换。 这个需要具体问题具体分析,在这个案例中,增删改调用的接口还蛮简单的,只用传对应id和修改值就行了。 调用成功后,需要重新获取一次数据,重新初始化一次。