最近被一个小小的前端数据处理脑子整的有点糊了,就是在大脑里整个的思路很简单,但是写完代码一跑确有问题,顿时陷入了思路和代码实现的对抗,改来改去最终是我总结的是对嵌套的for 循环不仔细分析是很容易出问题的。记录一下脑子糊了之后走不动的感受,教训是要慢下来,对自己的每一部分代码进行思路对应的检查。
第一版需求:
Select 病种选择,选择的数据在table 中进行展示,一类病种只能选择同一个医院,因此选择后的同类病种要放在一行中,数据展示按照选择的顺序展示,每一个病种可以单独删除。最终的效果图如下
实现思路,选择框选择的病种会选择到一个集合中,根据选择的集合,根据病种分类整理适合table 展示的数据,监听select控件的change时间,实现选择数据和下方table 的联动。每次change 都会按照当前的选择重新整合table 数据。
以上思路增加选择项的时候确实没有问题,按照选择的顺序 逆序删除也没有问题,但是选择框中的数据是按照选择顺序加入的,但是同类病种如果最先加入的被删除,change 时间触发后再整理table 数据,会导致table 原有数据上下行的交替,这种效果显然不符合正常的显示逻辑。
解决思路:
在整理table 数据之前,首先要把table 中已有的数据放在最前面,之后把新增的数据放在后面,再按照顺序整理table 数据
具体代码如下:
<template>
<div class="containerbox">
<el-select
v-model="selectedDiseases"
@change="changeDisease"
value-key="diseaseNo"
multiple
collapse-tags
style="margin-left: 20px;"
placeholder="请选择申请病重"
:multiple-limit="8"
popper-class="sort_select"
>
<el-option v-for="item in allDisease" :key="item.diseaseNo" :label="item.diseaseName" :value="item"> </el-option>
</el-select>
<el-table :data="tableData" style="width: 100%" border center>
<el-table-column label="选择申请病种" :min-width="180" align="center">
<template slot-scope="scope">
<!-- -->
<span class="diseaseItem" v-for="item in scope.row.itemInfo" :key="item.diseaseNo"
>{{ item.diseaseName }}
<el-button type="text" class="el-icon-remove-outline" @click="removeDisease(item)"></el-button>
</span>
</template>
</el-table-column>
<el-table-column prop="fixhospitalName" label="选择医院" :min-width="180" align="center"> </el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="primary" @click="chooseHospital(scope.row)">请选择医院</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import diseaseData from './disease.json'
export default {
data() {
return {
tableData: [],
allDisease: [],
selectedDiseases: [],
diseasesDto: []
}
},
methods: {
changeDisease(arr) {
// 执行分组显示的问题
// console.log(arr)
// 根据当前选中的和之前选中的数据整合新的table 中应该展示的数据
const tempTableData = this.tableData
this.diseasesDto = []
const oldDatas = []
const newAdds = []
this.tableData.forEach(row => {
row.itemInfo.forEach(item => {
oldDatas.push(item)
})
})
// 先在新的选项中找到原来讯在的保留
oldDatas.forEach(item => {
const index = arr.findIndex(newItem => {
return item.diseaseNo == newItem.diseaseNo
})
if (index != -1) {
this.diseasesDto.push(item)
}
})
// 把原来没加进去新增的加进入
arr.forEach(item => {
const index = this.diseasesDto.findIndex(inItem => {
return inItem.diseaseNo == item.diseaseNo
})
if (index == -1) {
this.diseasesDto.push(JSON.parse(JSON.stringify(item)))
}
})
//从当前选中的病中深拷贝 1、如果已经是已经选择了医院的 保留医院 如果
this.tableData = []
this.diseasesDto.forEach(deepObj => {
// 创建深拷贝的对象
// const deepObj = JSON.parse(JSON.stringify(item))
// 先判断tableData 中是否有这类数据 如果没有创建新的对象加入table data ,如果有的话在对应的itemInfo 中加入对应的item
if (this.tableData.length == 0) {
//还没加入过数据
this.tableData.push({ fixhospitalName: deepObj.fixhospitalName, itemInfo: [deepObj] })
} else {
// 已经有数据 遍历里面的数据判断是否有这样的一类
let inTable = false
this.tableData.some(row => {
//
if (row.itemInfo[0].categoryNo == deepObj.categoryNo) {
row.itemInfo.push(deepObj)
inTable = true
}
})
if (!inTable) {
//如果没有在table 中 创建一个对象计入
console.log('======')
this.tableData.push({ fixhospitalName: deepObj.fixhospitalName, itemInfo: [deepObj] })
}
}
})
// console.log(this.tableData)
},
removeDisease(disease) {
//删除选中集合中对应的数据
const index = this.selectedDiseases.findIndex(item => {
return item.diseaseNo == disease.diseaseNo
})
console.log(index)
this.selectedDiseases.splice(index, 1)
this.changeDisease(this.selectedDiseases)
// this.tableData.some((item, rowIndex) => {
// const findedIndex = item.itemInfo.findIndex((ii, index) => {
// //判断如果有的话直接删除 删除后如果
// if (ii.diseaseNo == disease.diseaseNo) {
// item.itemInfo.splice(index, 1)
// }
// return ii.diseaseNo == disease.diseaseNo
// })
// if (findedIndex != -1) {
// // 判断删除后的row 是否还有信息
// if (item.itemInfo.length == 0) {
// this.tableData.splice(rowIndex, 1)
// }
// return true
// }
// })
// 删除table 中对应的数据
}
},
mounted() {
this.allDisease = diseaseData
//生成模拟数据
// const categoryNos = ['01', '02', '03', '04']
// const categoryNames = ['精神类', '皮肤类', '结核类', '其他']
// for (let i = 0; i < 20; i++) {
// const random = Math.floor(Math.random() * 4)
// const disease = {}
// disease.diseaseNo = '0' + i
// disease.diseaseName = '疾病' + i
// disease.categoryNo = categoryNos[random]
// disease.categoryName = categoryNames[random]
// this.allDisease.push(disease)
// }
}
}
</script>
<style lang="scss">
.containerbox {
padding: 30px;
text-align: center;
.el-select {
margin-top: 50px;
}
.el-table {
margin-top: 200px;
}
.diseaseItem {
margin-right: 20px;
.el-button {
color: red;
// i {
// color: red;
// }
}
}
}
</style>
需求改版:
需求刚写完的两天,因为要增加备足需求有变,改变后的需求涉及到单元格的合并单元格的需求,每个兵种占一行,增加备注列,其他操作和医院同一类的合并单元格,我的思路是,合并单元格仍然需要原来整理的tale 数据,因此保留,稍微改下页面渲染的数据结构,增加单元格合并的操作,效果图类似如下:
最终代码如下:
<template>
<div class="containerbox">
<el-select
v-model="selectedDiseases"
@change="changeDisease"
value-key="diseaseNo"
multiple
collapse-tags
style="margin-left: 20px;"
placeholder="请选择申请病重"
:multiple-limit="8"
popper-class="sort_select"
>
<el-option v-for="item in allDisease" :key="item.diseaseNo" :label="item.diseaseName" :value="item"> </el-option>
</el-select>
<el-table :data="tableDataList" style="width: 100%" border center :span-method="tableSpanMethod">
<el-table-column label="选择申请病种" :min-width="180" align="center">
<template slot-scope="scope">
<!-- -->
<span class="diseaseItem" :key="scope.row.diseaseNo"
>{{ scope.row.diseaseName }}
<el-button type="text" class="el-icon-remove-outline" @click="removeDisease(scope.row)"></el-button>
</span>
</template>
</el-table-column>
<el-table-column prop="fixhospitalName" label="选择医院" :min-width="180" align="center"> </el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="primary" @click="chooseHospital(scope.row)">请选择医院</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import diseaseData from './disease.json'
export default {
data() {
return {
tableDataList :[],
tableData: [],
allDisease: [],
selectedDiseases: [],
diseasesDto: []
}
},
methods: {
changeDisease(arr) {
// 执行分组显示的问题
// console.log(arr)
// 根据当前选中的和之前选中的数据整合新的table 中应该展示的数据
// const tempTableData = this.tableData
this.diseasesDto = []
const oldDatas = []
const newAdds = []
// this.tableData.forEach(row => {
// row.itemInfo.forEach(item => {
// oldDatas.push(item)
// })
// })
// 先在新的选项中找到原来讯在的保留
this.tableDataList.forEach(item => {
const index = arr.findIndex(newItem => {
return item.diseaseNo == newItem.diseaseNo
})
if (index != -1) {
this.diseasesDto.push(item)
}
})
// 把原来没加进去新增的加进入
arr.forEach(item => {
const index = this.diseasesDto.findIndex(inItem => {
return inItem.diseaseNo == item.diseaseNo
})
if (index == -1) {
this.diseasesDto.push(JSON.parse(JSON.stringify(item)))
}
})
//从当前选中的病中深拷贝 1、如果已经是已经选择了医院的 保留医院 如果
this.tableData = []
this.diseasesDto.forEach(deepObj => {
// 创建深拷贝的对象
// const deepObj = JSON.parse(JSON.stringify(item))
// 先判断tableData 中是否有这类数据 如果没有创建新的对象加入table data ,如果有的话在对应的itemInfo 中加入对应的item
if (this.tableData.length == 0) {
//还没加入过数据
this.tableData.push({ fixhospitalName: deepObj.fixhospitalName, itemInfo: [deepObj] })
} else {
// 已经有数据 遍历里面的数据判断是否有这样的一类
let inTable = false
this.tableData.some(row => {
//
if (row.itemInfo[0].categoryNo == deepObj.categoryNo) {
row.itemInfo.push(deepObj)
inTable = true
}
})
if (!inTable) {
//如果没有在table 中 创建一个对象计入
console.log('======')
this.tableData.push({ fixhospitalName: deepObj.fixhospitalName, itemInfo: [deepObj] })
}
}
})
// 修改策略 需要单独按照顺序拿出来每一个数据 之后再合并单元格
this.tableDataList = []
this.tableData.forEach(row=>{
row.itemInfo.forEach(item=>{
this.tableDataList.push(item)
})
})
// console.log(this.tableData)
},
removeDisease(disease) {
//删除选中集合中对应的数据
const index = this.selectedDiseases.findIndex(item => {
return item.diseaseNo == disease.diseaseNo
})
console.log(index)
this.selectedDiseases.splice(index, 1)
this.changeDisease(this.selectedDiseases)
// this.tableData.some((item, rowIndex) => {
// const findedIndex = item.itemInfo.findIndex((ii, index) => {
// //判断如果有的话直接删除 删除后如果
// if (ii.diseaseNo == disease.diseaseNo) {
// item.itemInfo.splice(index, 1)
// }
// return ii.diseaseNo == disease.diseaseNo
// })
// if (findedIndex != -1) {
// // 判断删除后的row 是否还有信息
// if (item.itemInfo.length == 0) {
// this.tableData.splice(rowIndex, 1)
// }
// return true
// }
// })
// 删除table 中对应的数据
},
tableSpanMethod({row,column,rowIndex,columnIndex}){
//合并单元格
let spanList = []
this.tableData.forEach(row=>{
spanList.push({spanLen:row.itemInfo.length,spanIndex:0})
})
// 需要合并单元格的列
if(columnIndex==1||columnIndex==2){
let spanStartIndex = 0;
spanList.forEach(item=>{
item.spanIndex = spanStartIndex
spanStartIndex +=item.spanLen
})
let spaned = false
for(let i = 0;i<spanList.length;i++){
if(rowIndex === spanList[i].spanIndex){
spaned = true
return {
rowspan:spanList[i].spanLen,
colspan:1
}
}
}
}
}
},
mounted() {
this.allDisease = diseaseData
//生成模拟数据
// const categoryNos = ['01', '02', '03', '04']
// const categoryNames = ['精神类', '皮肤类', '结核类', '其他']
// for (let i = 0; i < 20; i++) {
// const random = Math.floor(Math.random() * 4)
// const disease = {}
// disease.diseaseNo = '0' + i
// disease.diseaseName = '疾病' + i
// disease.categoryNo = categoryNos[random]
// disease.categoryName = categoryNames[random]
// this.allDisease.push(disease)
// }
}
}
</script>
<style lang="scss">
.containerbox {
padding: 30px;
text-align: center;
.el-select {
margin-top: 50px;
}
.el-table {
margin-top: 200px;
}
.diseaseItem {
margin-right: 20px;
.el-button {
color: red;
// i {
// color: red;
// }
}
}
}
</style>
以上记录一次有印象的数据处理 github 完整代码在demo 中 sortDemo.vue 文件