业务场景:(如下图所示)
【从上图可以知道,这是很常见的多tab切换场景,切换时,下面的 table数据会发生变化,而且页面的上的操作按钮也需要在当前table页完成操作】
具体业务:(如下图所示)
优化前:(究极不科学,不推荐)
由于每个table的表头字段基本都不同,最初为了图省事,就v-if了6个table,来分别展示不同的table,后端就没怎么改动,只需要前端自己判断下就行了。 这样做的后果就是:代码沉积,垃圾代码太多了,看也看得心烦,更恐怖的是,如果是6个table,那么就应该有6个编辑的模态框,代码量更多了,而且本来这个tab就是动态的,要是后面要什么改动的话,真的会把心态搞崩的,严重影响摸鱼的时间。
优化后:
既然都说了,不能用多个table来分别展示,那就用一个table来展示呗,只是后端会稍微改一下,所以说以后和后端谁主动谁方便, 我直接把刀架在他脖子上,提出了几点关于这个地方的优化意见:
- 表头的问题---------开始用6个table的时候我是写死的,现在要你返数据的时候把表头list给我,我自己来动态渲染
- 既然表头都是动态的了,那么【新增】【编辑】这两个按钮点击的时候,你应该出一个单独的接口,让我优雅地获取到字段数据,格式我来定,达到 切换到每一类的时候,都能够 新增/编辑 对应的字段信息
效果如下图所示:
新增
编辑
代码局部分析:
1.1 表格数据格式 返回的data里面包含下面这些小标题和里面的数据
keys是需要传给后端的字段信息(顺序不会随浏览器的ASC码排序而打乱,如果是object,浏览器会对里面的key进行ASC排序)
names就是我需要遍历渲染的表头信息,
values就是table需要展示的数据
keys: ["auto_increment_id", "time_create", "serial", "opportunity_id", "name", "manufacturer", "model",…]
names: {time_create: "添加时间", serial: "设备唯一编码", opportunity_id: "商机编码", name: "设备名称", manufacturer: "生产厂家",…}
number: 5
total: 14
values: [,…]
1.2 v-for 对象,请求接口完成以后,需要对table的表头进行渲染
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column type="index" width="55" label="序号"></el-table-column>
<el-table-column :prop="kk" :label="val" width="200" v-for="(val,kk,index) in t_header" :key="index"></el-table-column>
在data里面定义{
t_header:{},
}
请求的时候 返回的names 赋值给 t_header 即可
重点和难点
2.1 点击 新增/编辑 时,先请求一个获取字段信息的接口,渲染出模态框里面的内容
req 参数:
{opportunity_id: "Leo的商机编码-1", srvtype_dispname: "前端感知源类"}
res 数据:[data]
这里需要做一个区分
values.length = 0 输入框
values.length > 0 下拉框
field是需要提交给后端的字段
name是用于页面展示的字段
0: {field: "name", name: "设备名称", values: []}
1: {field: "manufacturer", name: "生产厂家", values: []}
2: {field: "model", name: "设备型号", values: []}
3: {field: "type", name: "设备类型",…}
4: {field: "state", name: "设备状态", values: [{value: "正常"}, {value: "停用"}, {value: "维修"}, {value: "退网"}]}
5: {field: "varchar_0", name: "像素", values: []}
6: {field: "manage_ip", name: "管理IP", values: []}
7: {field: "varchar_1", name: "功能类型",…}
8: {field: "location_city", name: "设备安装位置-地市", values: []}
9: {field: "location_county", name: "设备安装位置-区县", values: []}
10: {field: "location_street", name: "设备安装位置-街道", values: []}
11: {field: "location_detail", name: "设备安装位置-详细地址", values: []}
12: {field: "longitude", name: "经度", values: []}
13: {field: "latitude", name: "纬度", values: []}
14: {field: "maintainer", name: "运维方", values: [{value: "1111"}, {value: "5555"}]}
15: {field: "ct_number", name: "关联专线",…}
16: {field: "ct_terminal_port", name: "专线末端设备下行端口号", values: []}
【数据的问题解决了,那么接下来才是最重要,最麻烦的...】
2.2 新增/编辑 按钮 , 点击以后请求接口,得到上面的数据,再构造自己需要的数据
弹出 设备信息列表(获取输入表单字段)
handleShebei() {
这里用到了arguments是因为 下面由于作用域的关系,不得不给这个函数加个回调作为它的形参,便于下一步
if(arguments.length == 1 && arguments[0]){
this.dialogShebei = true; 只有一个参数的情况
}
if(this.my_lock){
if(arguments.length == 2 && arguments[1]){
(arguments[1])() 只有两个参数的情况 立即调用第二个回调参数
}
return false
}else{
this.$axios({
url: "",
responseType: "json",
method: "POST",
data: {
opportunity_id: "",
srvtype_dispname: "",
},
})
.then((data) => {
// console.log(data);
let _data = data.data;
if (data.status == 200) {
let em = []; em开头的都代表 输入框
let all = []; all开头的都代表 下拉框
_data.forEach((v) => {
if (v.values.length == 0) {
em.push(v);
} else {
all.push(v);
}
});
// console.log(em);
// console.log(all);
em.forEach((v) => {
this.em_arr.push({
key: v.field,
label: v.name,
value: v.values.join(),
});
});
all.forEach((v) => {
this.all_arr.push({
key: v.field,
label: v.name,
value: "",
options: v.values,
});
});
this.my_lock = true
// console.log(this.em_arr);
// console.log(this.all_arr);
代码到这里结束,能够打印出分好类的 输入框 和 下拉框 所需要的的数据了
下面这几行代码 就是由于 在另外一个函数里面访问不到 this.em_arr_edt 和 this.all_arr_edt
存在异步的问题,所以才考虑用远古解决异步的方式————嵌入回调式
别问为什么,问就应该用 promise
this.em_arr_edt = JSON.parse(JSON.stringify(this.em_arr))
this.all_arr_edt = JSON.parse(JSON.stringify(this.all_arr))
if(arguments.length == 2 && arguments[1]){
(arguments[1])()
}
}
})
}
},
点击编辑按钮时,处理的函数
handelsrv_edit(row) {
this.dialogSrv = true;
this.handleShebei(0,()=>{ 这里就是 用了 嵌入回调式, 最方便的地方
console.log('原始数据',row);
console.log(this.em_arr_edt);
console.log(this.all_arr_edt); 能访问到 需要的数据,从而顺利完成编辑功能
for (const k in row) {
this.em_arr_edt.forEach(v =>{
if(v.key === k)
v.value = row[k]
})
this.all_arr_edt.forEach(v =>{
if(v.key === k)
v.value = row[k]
})
}
})
},
总结:
- 对于多tab 切换类的业务组件,用一个table展示,不用多个table来做if判断
- 尤其是每个table还有 “增删改查”的时候,更需要代码的可读性和可维护性
- 在处理异步问题的时候,除了promise,有时候 回调嵌套也有方便的时候,仅限回调很少的时候