关于表格合并span-method方法的补充(表格数据由后台动态返回)

之前写了一些关于element-ui表格合并的方法,不过用的数据都是确定的数据(死数据),但是很多时候我们的数据都是通过后台获得的,数据不稳定,这个时候使用表格合并就需要先处理一下数据,先看一下一种很常见的数据展示场景
本博客源码: https://github.com/shengbid/vue-demo  这个项目里会把平时博客写的一些功能的代码都放在里面,有需要可以下载看看,有帮助的话点个star哈
 
 
直接上代码,HTML代码就不放了,都是差不多的,下面另一种场景有
// 模拟后台返回的值
    getTable () {
      this.tableData = [{
        id: 1,
        region: '中国',
        type: [{
          sortName: '器械',
          sortList: [{
            name: '器械1'
          }, {
            name: '器械2'
          }]
        }, {
          sortName: '软件',
          sortList: [{
            name: '软件1'
          }, {
            name: '软件2'
          }, {
            name: '软件3'
          }]
        }]
      }, {
        id: 2,
        region: '美国',
        type: [{
          sortName: '器械',
          sortList: [{
            name: '器械1'
          }, {
            name: '器械2'
          }]
        }, {
          sortName: '软件',
          sortList: [{
            name: '软件1'
          }, {
            name: '软件2'
          }]
        }]
      }]
      this.dealTable()
    },

    // 处理表格数据
    dealTable () {
      let getDate = [] // 存储新表格数据
      let typeIndex = [0] // 保存id,地区需要合并的值
      let nameIndex = [0] // 保存类型需要合并的值
      let a // id,地区需要合并的行是所有类型的长度
      this.tableData.forEach((v, index) => {
        if (v.type && v.type.length) {
          a = 0
          v.type.forEach((subV, i, typeData) => {
            if (subV.sortList && subV.sortList.length) {
              subV.sortList.forEach((ss, k, data) => {
                if (k === data.length - 1) {
                  typeIndex.push(data.length) // 把每一个类型下面数据长度存起来
                  a += data.length // 把所有类型下面的数据长度相加
                  if (i === typeData.length - 1) {
                    nameIndex.push(a) // 类型循环完成后把数据长度存起来
                  }
                }
                getDate.push({
                  id: v.id,
                  region: v.region,
                  type: subV.sortName,
                  name: ss.name
                })
              })
            }
          })
        }
      })

      console.log(nameIndex)
      // [0, 5, 4]
      // 看一下打印出来的规律,除去第一项,5是第一次需要合并的行
      // 第二次合并又是从第五行开始合并4行

      console.log(typeIndex)
      // [0, 2, 3, 2, 2]
      // 类型的数据存储规律也是一样,第一次合并2行
      // 第二次从2行开始,合并3行,以此类推

      // 根据这个规则,只需要给数据加上两个额外的属性控制是否合并就OK
      let k = 0
      let t = 0
      nameIndex.forEach((v, i, nameArr) => {
        if (nameArr[i + 1]) {
          getDate[k].nameIndex = nameArr[i + 1]
          k += nameArr[i + 1]
        }
      })

      typeIndex.forEach((v, i, typeArr) => {
        if (typeArr[i + 1]) {
          getDate[t].typeIndex = typeArr[i + 1]
          t += typeArr[i + 1]
        }
      })
      this.tableData6 = getDate
      console.log(getDate)
      // 0: {id: 1, name: "器械1", nameIndex: 5, region: "中国", type: "器械", typeIndex: 2},
      // 1: {id: 1, name: "器械2", region: "中国", type: "器械"}
      // ....
      // 5: {id: 2, name: "器械1", nameIndex: 4, region: "美国", type: "器械", typeIndex: 2}
    },

    // 表格合并方法
    arraySpanMethod ({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0 || columnIndex === 1) {
        if (row.nameIndex) { // 如果有值,说明需要合并
          return [row.nameIndex, 1]
        } else return [0, 0]
      }
      if (columnIndex === 2) {
        if (row.typeIndex) {
          return [row.typeIndex, 1]
        } else return [0, 0]
      }
    },

 

 
再说一下另一种场景,用的另一种方法实现,原理都是大同小异
 
 
假设后台返回的数据是这样的:
 
 
在这种情况下,一般我们会选择对行进行合并,因为这时候表格的列是知道的,只要把需要合并的列提取出来,合并行就OK,下面看代码

HTML代码
<el-table
    :data="tableData6"
    :span-method="arraySpanMethod"
    border
    style="width: 100%">
    <el-table-column
      prop="id"
      label="ID"
      width="180">
    </el-table-column>
    <el-table-column
      prop="region"
      label="深圳">
    </el-table-column>
    <el-table-column
      prop="type"
      label="类型">
    </el-table-column>
    <el-table-column
      prop="company"
      label="企业名称">
    </el-table-column>
  </el-table>

 

js代码,首先需要处理一下后台数据
 
getIndex () {
      let arr = []
      let s = 0
      let table = this.tableData6
      let getTable = []
      table.forEach((item, i, data) => {
        if (arr.length) {
          s = arr[arr.length - 1].row + data[i - 1].company.length
        }
        arr.push({
          row: s,
          index: item.company.length
        })
        if (item.company && item.company.length) {
          item.company.forEach(subItem => {
            getTable.push({
              id: item.id,
              region: item.region,
              type: item.type,
              company: subItem.name
            })
          })
        }
      })
      this.arr = arr
      this.tableData6 = getTable
    },

 

数据处理之后就进行表格合并
// 合并表格方法
    arraySpanMethod ({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) {
        let obj = [0, 0]
        this.arr.some(v => {
          if (rowIndex === v.row) {
            obj = [v.index, 1]
          }
        })

        return obj
      }
    }

 

PS: 在这里说一下楼主遇到的一个坑,其实也是因为对函数的return不熟悉造成的,一开始我是这样写的,
 
结果页面一直不对,debugger了一下,发现函数中根本没接收到return回去的数据,这是因为我return之后又写了代码,函数真正结束时没有返回值.所以在函数中,return之后就不要在写执行代码了.
 
正确的写法后debugger就能接收到正确的返回值了
 
 

补充内容:

后面自己又整理了一下,写了一个公共方法,可以处理两层合并和三层合并,完整代码,这是一个完整的vue代码,可以直接复制到代码中看效果

<template>
  <div style="padding:30px;">
    <h2>后台返回数据动态合并(根据后台返回的数据进行表格合并)</h2>
    <p>
      两层数据合并
    </p>
    <el-table
      :data="tableData2"
      :span-method="arraySpanMethod2"
      border
      style="width: 100%;"
    >
      <el-table-column
        prop="id"
        label="ID"
        width="180"
      />
      <el-table-column
        prop="region"
        label="地区"
      />
      <el-table-column
        prop="type"
        label="类型"
      />
    </el-table>
    <!-- 表格2 -->
    <p style="margin-top: 40px">
      三层数据合并
    </p>
    <el-table
      :data="tableData"
      :span-method="arraySpanMethod"
      border
      style="width: 100%"
    >
      <el-table-column
        prop="id"
        label="ID"
        width="180"
      />
      <el-table-column
        prop="region"
        label="地区"
      />
      <el-table-column
        prop="type"
        label="类型"
      />
      <el-table-column
        prop="name"
        label="产业"
      />
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: [],
      tableData2: []
    }
  },
  created() {
    this.getTable()
  },
  methods: {
    getTable() {
      const tableData = [{
        id: 1,
        region: '中国',
        type: [{
          sortName: '器械',
          sortList: [{
            name: '器械1'
          }, {
            name: '器械2'
          }]
        }, {
          sortName: '软件',
          sortList: [{
            name: '软件1'
          }, {
            name: '软件2'
          }, {
            name: '软件3'
          }]
        }]
      }, {
        id: 2,
        region: '美国',
        type: [{
          sortName: '器械',
          sortList: [{
            name: '器械1'
          }, {
            name: '器械2'
          }]
        }, {
          sortName: '软件',
          sortList: [{
            name: '软件1'
          }, {
            name: '软件2'
          }]
        }]
      }, {
        id: 3,
        region: '加拿大',
        type: [{
          sortName: '器械',
          sortList: [{
            name: '器械1'
          }]
        }]
      }]
      this.dealTable(tableData)
      this.dealTable(tableData, 2)
    },

    // 处理表格数据(level,表格合并的层级)
    dealTable(tableData, level = 3) {
      const getDate = [] // 存储新表格数据
      let a // id,地区需要合并的行是所有类型的长度
      tableData.forEach((v, index) => {
        if (v.type && v.type.length) {
          a = 0
          v.type.forEach((subV, i, typeData) => {
            if (level === 2) { // 处理两层合并数据
              const obj = {
                id: v.id,
                region: v.region,
                type: subV.sortName
              }
              if (i === 0) {
                obj.typeIndex = typeData.length
              }
              getDate.push(obj)
            } else if (subV.sortList && subV.sortList.length) {
              subV.sortList.forEach((ss, k, data) => {
                const obj = {
                  id: v.id,
                  region: v.region,
                  type: subV.sortName,
                  name: ss.name
                }
                if (k === 0) {
                  obj.typeIndex = data.length
                }
                getDate.push(obj)
                if (k === data.length - 1) {
                  a += data.length // 把所有类型下面的数据长度相加
                  if (i === typeData.length - 1) {
                    getDate[getDate.length - a ].nameIndex = a
                  }
                }
              })
            }
          })
        }
      })

      if (level === 2) {
        this.tableData2 = getDate
      } else {
        this.tableData = getDate
      }
      console.log(getDate)
      // 0: {id: 1, name: "器械1", nameIndex: 5, region: "中国", type: "器械", typeIndex: 2},
      // 1: {id: 1, name: "器械2", region: "中国", type: "器械"}
      // ....
      // 5: {id: 2, name: "器械1", nameIndex: 4, region: "美国", type: "器械", typeIndex: 2}
    },

    // 表格合并方法(三层数据)
    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0 || columnIndex === 1) {
        if (row.nameIndex) { // 如果有值,说明需要合并
          return [row.nameIndex, 1]
        } else return [0, 0]
      }
      if (columnIndex === 2) {
        if (row.typeIndex) {
          return [row.typeIndex, 1]
        } else return [0, 0]
      }
    },
    // 表格合并方法(两层数据)
    arraySpanMethod2({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0 || columnIndex === 1) {
        if (row.typeIndex) { // 如果有值,说明需要合并
          return [row.typeIndex, 1]
        } else return [0, 0]
      }
    }
  }
}
</script>

 

表格后边后默认只有合并部分的第一行鼠标移入高亮,如果有hover样式的需求可以看这一篇博客https://www.cnblogs.com/steamed-twisted-roll/p/10469887.html

补充内容:

如果表格的层级不确定,或者层级比较多,多次循环写的很麻烦,可以参考我最近整理的这篇,动态层级的表格合并,是一个通用的合并处理方法, 2-5级的表格合并都试验了没问题,其他更多层级的需求也可以用

children为空和不为空的情况也处理了

链接: https://www.cnblogs.com/steamed-twisted-roll/p/17109524.html

posted @ 2018-11-07 12:25  潇湘羽西  阅读(9324)  评论(6编辑  收藏  举报