vue使用element动态计算合并单元格及合并后hover样式高亮问题

933 阅读3分钟

最近一个需求涉及表格的动态合并,写完之后在这里记录一下实现过程,有需要的可以参考一下

大致效果图

image.png 主要的实现逻辑就是根据后端返回的数据中的唯一ID进行动态计算合并

1、可以通过比对上下数据是否相同来进行合并,所以首先需要把后端返回的数据进行处理。

示例
// 后端返回数据
const a = [
  {
    id: 1,
    country: '美国',
    address: '洛杉矶',
    work: '销售',
    height: '180cm',
    children: [
      { name: '李四', age: 18,  cid: 1 },
      { name: '王五', age: 18,  cid: 2 }
    ]
  },
  {
    id: 2,
    country: '英国',
    address: '伦敦',
    work: '收银',
    children: [
      { name: '赵六', age: 18,  cid: 3 },
    ]
  },
]

//需要处理成的数据格式
const b = [
  { id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '李四', age: 18, cid: 1 },
  { id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '王五', age: 18, cid: 2 },
  { id: 2, country: '英国', address: '伦敦',  work: '收银', name: '赵六', age: 18, cid: 3 },
]
//cid用于给表格添加row-key 所以cid必须是唯一值不能重复

这样就会根据比对上下两条数据是否相同来进行合并

合并主要是通过el-tablespan-method方法进行合并

<template>
  <div>
    <el-table 
    row-key="cid" 
    border 
    :data="tableData" 
    :span-method="mergeCellsMethod"  
    highlight-current-row
    >
      <el-table-column prop="country" label="国家"></el-table-column>
      <el-table-column prop="address" label="地址"></el-table-column>
      <el-table-column prop="work" label="工作"></el-table-column>
      <el-table-column prop="name" label="姓名"></el-table-column>
      <el-table-column prop="age" label="年龄"></el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: [
        { id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '李四', age: 18, cid: 1 },
        { id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '王五', age: 18, cid: 2 },
        { id: 2, country: '英国', address: '伦敦', work: '收银', name: '赵六', age: 18, cid: 3 }
      ]
    }
  },
  methods: {
    mergeCellsMethod({ row, column, rowIndex }) {
    // 根据行id进行合并,这样不会导致上下数据相同但id不同时会合并错误的问题
      switch (column.property) {
        case 'country': 
          return this.setTableRowCol(row, rowIndex, ['id', 'country'])
        case 'address':
          return this.setTableRowCol(row, rowIndex, ['id', 'address'])
        case 'work':
          return this.setTableRowCol(row, rowIndex, ['id', 'work'])
        default:
          break
      }
    },
    setTableRowCol(row, rowIndex, keys) {
      let firstIndex = 0
      let rowspan = 1
      let colspan = 1
      // 找到需要合并的行的下标
      firstIndex = this.tableData.findIndex((item) => {
        return this.filterSameKeys(item, row, keys)
      })
      if (rowIndex === firstIndex) {
        // 需要合并的行数
        rowspan = this.tableData.filter((item) => {
          return this.filterSameKeys(item, row, keys)
        }).length
        colspan = 1
      } else {
        // 被合并的行需要设置成0
        rowspan = 0
        colspan = 0
      }
      return {
        rowspan,
        colspan
      }
    },
    // 根据keys数组所有字段去做合并
    filterSameKeys(item, row, keys) {
      let flag = true
      keys.forEach((key) => {
        flag = flag && item[key] === row[key]
      })
      return flag
    }
  }
}
</script>

以下是上述代码运行后的结果 image.png 也可以这样

image.png 只需要在mergeCellsMethod方法中根据字段名去匹配即可
2、但是在上图可以看到合并之后hover的样式不是我们预想的效果
我们可以通过cell-mouse-entercell-mouse-leave事件以及row-class-name方法来解决

 // methods
 // 鼠标移入
    cellMouseEnter(row) {
    //currentIndex在data中定义,我这里就不写了
      this.currentIndex = row.id
    },
    // 鼠标移出
    cellMouseLeave() {
      this.currentIndex = ''
    },
    // 设置行class
    tableRowClassName({ row }) {
      let flag = row.id === this.currentIndex
      return flag ? 'table-hover-row' : ''
    }
    
 //style 
 // 注意!!!!处理hover样式不加scoped才能生效
<style lang="scss">
    .el-table .table-hover-row {
      background: #e0f3ff !important;
    }
    .el-table tbody tr:hover > td {
      background-color: #e0f3ff !important;
    }
</style>

image.png 这样hover样式就解决了 如果是点击高亮有问题则同理使用row-click事件给currentIndex赋值即可。

先写到这,如果有问题就发在评论区或者私信我