基于element-ui实现表格行列合并

280 阅读2分钟

效果

effect2.png

模板

<template>
  <div class="mergeColumns">
    <el-table :data="tableData" style="width: 100%" height="817px" :header-cell-style="headerStyle" :span-method="objectSpanMethod" :row-class-name="tableRowClassName" @cell-mouse-enter="cellMouseEnter"
      @cell-mouse-leave="cellMouseLeave">
      <el-table-column label="表头1" align="center">
        <el-table-column label="h1" prop="h1" align="center" show-overflow-tooltip> </el-table-column>
        <el-table-column label="h2" prop="h2" align="center" show-overflow-tooltip> </el-table-column>
        <el-table-column label="h3" prop="h3" align="center" show-overflow-tooltip> </el-table-column>
        <el-table-column label="h4" prop="h4" align="center" show-overflow-tooltip> </el-table-column>
      </el-table-column>
      <el-table-column prop="field2" label="表头2"> </el-table-column>
      <el-table-column prop="field3" label="表头3"> </el-table-column>
    </el-table>
  </div>
</template>

数据

[
  {
    h1: '投资',
    h2: '投资估算(万元)',
    h3: '',
    h4: '',
    field2: 'field2',
    field3: 'field3',
  },
  {
    h1: '工程名称',
    h2: '',
    h3: '',
    h4: '',
    field2: 'field2',
    field3: 'field3',
  },
  {
    h1: '自然条件',
    h2: '污秽等级',
    h3: '',
    h4: '',
    field2: 'field2',
    field3: 'field3',
  },
  {
    h1: '自然条件',
    h2: '海拔(m)',
    h3: '',
    h4: '',
    field2: 'field2',
    field3: 'field3',
  },
  {
    h1: '自然条件',
    h2: '地形地貌统计',
    h3: '',
    h4: '',
    field2: 'field2',
    field3: 'field3',
  },
]

逻辑

import { partialData } from './data'
export default {
  props: {
    // 并并列属性(约束条件连续且唯一)
    mergeProps: {
      type: Array,
      default: () => ['h1', 'h2', 'h3', 'h4']
    },
    // 斑马纹 (非element-ui中的斑马纹效果)
    stripe: {
      type: Boolean,
      default: true
    },
  },
  data() {
    return {
      tableData: partialData, // 表格源数据
      colspanConfig: {},

      // 悬浮时行背景色处理
      rowIndex: "-1",
      OrderIndexArr: [], // 合并行索引集合
      hoverOrderArr: [],
    }
  },
  mounted() {
    if (this.mergeProps && this.mergeProps.length) {
      this.init()
      this.getOrderNumber()
    }
  },
  methods: {
    // 计算合并规则
    init() {
      let len = this.tableData.length - 1;
      // 合并规则初始配置
      for (let i = len; i >= 0; i--) {
        let rowKey = `row_${i}`
        this.mergeProps.forEach(prop => {
          if (this.colspanConfig[rowKey]) {
            this.colspanConfig[rowKey][prop] = {
              rowspan: 1,
              colspan: 1,
            }
          } else {
            this.colspanConfig[rowKey] = {
              [prop]: {
                rowspan: 1,
                colspan: 1,
              }
            }
          }
        })
      }
      // 处理单元格合并规则
      for (let i = len; i >= 0; i--) {
        let rowKey = `row_${i}`
        let propLen = this.mergeProps.length - 1;
        // 列合并规则
        for (let k = propLen; k > 0; k--) {
          // 列值为空或与前一列值相同时,则合并
          if (!this.tableData[i][this.mergeProps[k]] || this.tableData[i][this.mergeProps[k]] === this.tableData[i][this.mergeProps[k - 1]]) {
            this.colspanConfig[rowKey][this.mergeProps[k - 1]].colspan = this.colspanConfig[rowKey][this.mergeProps[k]].colspan + 1
            this.colspanConfig[rowKey][this.mergeProps[k]].colspan = 0
          }
        }
        // 行合并规则
        for (let k = propLen; k >= 0; k--) {
          // 行值(不为空)与上一行值相同并且大组值相同,则合并
          if (this.tableData[i - 1] && this.tableData[i][this.mergeProps[k]] && (this.tableData[i][this.mergeProps[k]] === this.tableData[i - 1][this.mergeProps[k]]) && (this.tableData[i][this.mergeProps[0]] === this.tableData[i - 1][this.mergeProps[0]])) {
            this.colspanConfig[`row_${i - 1}`][this.mergeProps[k]].rowspan = this.colspanConfig[rowKey][this.mergeProps[k]].rowspan + 1;
            this.colspanConfig[rowKey][this.mergeProps[k]].rowspan = 0
          }
        }
      }
    },
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      let rowspan = 1;
      let colspan = 1
      if (this.mergeProps.includes(column.property)) {
        colspan = this.colspanConfig[`row_${rowIndex}`][column.property].colspan
        rowspan = this.colspanConfig[`row_${rowIndex}`][column.property].rowspan
      }
      return {
        rowspan,
        colspan,
      }
    },

    /** 
     * @description 分组 将合并的行索引分组
     */
    getOrderNumber() {
      var OrderObj = {};
      this.tableData.forEach((element, index) => {
        element.rowIndex = index;
        if (OrderObj[element[this.mergeProps[0]]]) {
          OrderObj[element.h1].push(index);
        } else {
          OrderObj[element[this.mergeProps[0]]] = [];
          OrderObj[element[this.mergeProps[0]]].push(index);
        }
      });
      for (var k in OrderObj) {
        if (OrderObj[k].length >= 1) {
          this.OrderIndexArr.push(OrderObj[k]);
        }
      }
    },
    /**
     * @description 为表格行设置动态类
     * @param {*} param0
     */
    tableRowClassName: function ({ row, rowIndex }) {
      var arr = this.hoverOrderArr;
      for (var i = 0; i < arr.length; i++) {
        if (rowIndex == arr[i]) {
          return "success-row";
        }
      }
      for (let i = 0; i < this.OrderIndexArr.length; i++) {
        if (this.OrderIndexArr[i].includes(rowIndex) && i % 2 === 0) {
          return 'high-light-row'
        }
      }
    },
    /**
     * 鼠标移入事件
     * @param {*} row
     * @param {*} column
     * @param {*} cell
     * @param {*} event
     * @description 查找移入行的组, 对组的每一项设置动态类
     */
    cellMouseEnter: function (row, column, cell, event) {
      this.rowIndex = row.rowIndex;
      this.hoverOrderArr = [];
      this.OrderIndexArr.forEach((element) => {
        if (element.indexOf(this.rowIndex) >= 0) {
          this.hoverOrderArr = element;
        }
      });
    },
    /**
     * 鼠标移出事件
     * @param {*} row
     * @param {*} column
     * @param {*} cell
     * @param {*} event
     * @description 移除行中的动态类
     */
    cellMouseLeave: function (row, column, cell, event) {
      this.rowIndex = "-1";
      this.hoverOrderArr = []; // 如果需要保留鼠标移出时的背景色,则保留当前行,反之注释
    },

    /**
     * 表头合并处理
     */
    headerStyle({ row, column, rowIndex, columnIndex }) {
      // if (this.mergeProps.includes(column.property)) {
      //   return "display: none;";
      // }
    },
  }
}

样式

/deep/.el-table {
  .success-row {
    background: #F4F9FD;
  }

  .high-light-row {
    background: #fafafa;
  }
}

// 移出时高亮异常 覆盖默认样式
/deep/.el-table--enable-row-hover {
  .el-table__body {
    tr:hover {
      td.el-table__cell {
        background-color: transparent;
      }
    }
  }
}