vue 中 表格相邻数据合并单元格

29 阅读4分钟

因为本人就喜欢粘了直接能用的demo, 在查找这个实现的时候看了太多人的废话 所以想要写一个在vue中粘贴直接能用的代码

长这样:左边是table标签 右边是el-table 1.png 代码:

<template>
  <div class="project-detail" ref="content">
    <div
      class="table-wrapper"
      style="display: flex; justify-content: space-between"
    >
      <!-- table 标签版 -->
      <table class="table">
        <!-- 表头 -->
        <tr class="tr head">
          <td style="width: 80px">序号</td>
          <td>姓名</td>
          <td>案号</td>
          <td>年龄</td>
          <td>体重</td>
        </tr>
        <!-- 表体 -->
        <tr v-for="(row, idx) in tableData" :key="idx">
          <td>
            {{ idx + 1 }}
          </td>
          <td v-if="row.nameSpan" :rowspan="row.nameSpan">
            {{ row.name }}
          </td>
          <td v-if="row.caseNumSpan" :rowspan="row.caseNumSpan">
            {{ row.caseNum }}
          </td>
          <td v-if="row.ageSpan" :rowspan="row.ageSpan">
            {{ row.age }}
          </td>
          <td v-if="row.weightSpan" :rowspan="row.weightSpan">
            {{ row.weight }}
          </td>
        </tr>
      </table>
      <!-- elementui版 -->
      <div style="width: 600px; border: 1px solid">
        <el-table :data="tableData" :span-method="objectSpanMethod" border>
          <el-table-column label="序号" width="80">
            <template slot-scope="scope">
              {{ scope.$index + 1 }}
            </template>
          </el-table-column>
          <el-table-column prop="name" label="姓名" align="center" />

          <el-table-column prop="caseNum" label="案号" align="center" />

          <el-table-column prop="age" label="年龄" align="center" />

          <el-table-column prop="weight" label="体重" align="center" />
        </el-table>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "demo",
  data() {
    return {
      tableData: [
        { name: "张三", caseNum: 2, age: 21, weight: 90 },
        { name: "张三", caseNum: 2, age: 21, weight: 90 },
        { name: "张三", caseNum: 2, age: 21, weight: 90 },
        { name: "张三", caseNum: 2, age: 25, weight: 90 },
        { name: "李四", caseNum: 8, age: 30, weight: 60 },
        { name: "李四", caseNum: 8, age: 25, weight: 60 },
        { name: "李四", caseNum: 8, age: 25, weight: 60 },
        { name: "李四", caseNum: 8, age: 23, weight: 60 },
        { name: "王五", caseNum: 8, age: 23, weight: 60 },
        { name: "王五", caseNum: 7, age: 30, weight: 60 },
        { name: "王五", caseNum: 7, age: 30, weight: 60 },
        { name: "王五", caseNum: 7, age: 25, weight: 70 },
        { name: "王五", caseNum: 7, age: 25, weight: 70 },
        { name: "王五", caseNum: 7, age: 25, weight: 70 },
      ],
    };
  },
  methods: {
    rowspanMethod(list) {
      for (let i = 0; i < list.length; i++) {
        let startRow;
        // 需要合并的行数
        let nameSpan = 1;
        // 循环到最后时
        if (i === list.length - 1) {
          // 当最后一行和倒数第二行属性不同 跳出循环
          if (list[i].name !== list[i - 1].name) {
            list[i].nameSpan = nameSpan;
          }
          break;
        }
        // 内层循环求需要合并的数量
        for (let j = i; j < list.length - 1; j++) {
          // 循环结束的行数
          startRow = j;
          // 属性相同则++
          if (list[j].name === list[j + 1].name) {
            nameSpan++;
          } else {
            // 属性不同跳出
            break;
          }
        }
        // 为数组添加你定义的rowspan属性
        list[i].nameSpan = nameSpan;
        // 控制外循环从内循环结束的行数开始
        i = startRow;
      }
      for (let i = 0; i < list.length; i++) {
        let startRow;
        let caseNumSpan = 1;
        if (i === list.length - 1) {
          // 因为要基于前面姓名相同才可以进行合并所以要加上name条件
          if (
            list[i].caseNum !== list[i - 1].caseNum &&
            list[i].name !== list[i - 1].name
          ) {
            list[i].caseNumSpan = caseNumSpan;
          }
          break;
        }
        for (let j = i; j < list.length - 1; j++) {
          startRow = j;
          // 这里也要加上条件
          if (
            list[j].caseNum === list[j + 1].caseNum &&
            list[j].name === list[j + 1].name
          ) {
            caseNumSpan++;
          } else {
            break;
          }
        }
        list[i].caseNumSpan = caseNumSpan;
        i = startRow;
      }
      for (let i = 0; i < list.length; i++) {
        let startRow;
        let ageSpan = 1;
        if (i === list.length - 1) {
          // 加上name caseNum 条件
          if (
            list[i].age !== list[i - 1].age &&
            list[i].caseNum !== list[i - 1].caseNum &&
            list[i].name !== list[i - 1].name
          ) {
            list[i].ageSpan = ageSpan;
          }
          break;
        }
        for (let j = i; j < list.length - 1; j++) {
          // 记录循环结束的行数
          startRow = j;
          // 加上name caseNum 条件
          if (
            list[j].age === list[j + 1].age &&
            list[j].caseNum === list[j + 1].caseNum &&
            list[j].name === list[j + 1].name
          ) {
            ageSpan++;
          } else {
            break;
          }
        }
        list[i].ageSpan = ageSpan;
        i = startRow;
      }
      for (let i = 0; i < list.length; i++) {
        let startRow;
        let weightSpan = 1;
        if (i === list.length - 1) {
          // 加上name caseNum age条件
          if (
            list[i].age !== list[i - 1].age &&
            list[i].caseNum !== list[i - 1].caseNum &&
            list[i].name !== list[i - 1].name &&
            list[i].weight !== list[i - 1].weight
          ) {
            list[i].weightSpan = weightSpan;
          }
          break;
        }
        for (let j = i; j < list.length - 1; j++) {
          startRow = j;
          // 加上name caseNum age条件
          if (
            list[j].age === list[j + 1].age &&
            list[j].caseNum === list[j + 1].caseNum &&
            list[j].name === list[j + 1].name &&
            list[j].weight === list[j + 1].weight
          ) {
            weightSpan++;
          } else {
            break;
          }
        }
        list[i].weightSpan = weightSpan;
        i = startRow;
      }
      this.tableData = list;
    },
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      // 姓名列合并
      if (column.property === "name") {
        const currentValue = row.name;
        const prevRow = this.tableData[rowIndex - 1];
        if (prevRow && prevRow.name === currentValue) {
          // 隐藏重复单元格
          return [0, 0];
        } else {
          // 计算相同的连续行数
          let rowspan = 1;
          for (let i = rowIndex + 1; i < this.tableData.length; i++) {
            if (this.tableData[i].name === currentValue) {
              rowspan++;
            } else {
              break;
            }
          }
          return [rowspan, 1];
        }
      }
      // 案号列合并
      if (column.property === "caseNum") {
        const currentValue = row.caseNum;
        const prevRow = this.tableData[rowIndex - 1];
        // 案号列合并有条件,需姓名相同
        if (
          prevRow &&
          prevRow.caseNum === currentValue &&
          row.name === prevRow.name
        ) {
          // 隐藏重复单元格
          return [0, 0];
        } else {
          // 计算相同的连续行数
          let rowspan = 1;
          for (let i = rowIndex + 1; i < this.tableData.length; i++) {
            if (
              this.tableData[i].caseNum === currentValue &&
              row.name === this.tableData[i].name
            ) {
              rowspan++;
            } else {
              break;
            }
          }
          return [rowspan, 1];
        }
      }
      //年龄列合并
      if (column.property === "age") {
        const currentValue = row.age;
        const prevRow = this.tableData[rowIndex - 1];
        // 年龄列合并有条件,需案号、姓名相同
        if (
          prevRow &&
          prevRow.age === currentValue &&
          row.caseNum === prevRow.caseNum &&
          row.name === prevRow.name
        ) {
          // 隐藏重复单元格
          return [0, 0];
        } else {
          let rowspan = 1;
          for (let i = rowIndex + 1; i < this.tableData.length; i++) {
            if (
              this.tableData[i].age === currentValue &&
              row.caseNum === this.tableData[i].caseNum &&
              row.name === this.tableData[i].name
            ) {
              rowspan++;
            } else {
              break;
            }
          }
          return [rowspan, 1];
        }
      }
      if (column.property === "weight") {
        const currentValue = row.weight;
        const prevRow = this.tableData[rowIndex - 1];
        if (
          prevRow &&
          prevRow.weight === currentValue &&
          row.caseNum === prevRow.caseNum &&
          row.name === prevRow.name &&
          row.age === prevRow.age
        ) {
          return [0, 0]; // 隐藏重复单元格
        } else {
          let rowspan = 1;
          for (let i = rowIndex + 1; i < this.tableData.length; i++) {
            if (
              this.tableData[i].weight === currentValue &&
              row.caseNum === this.tableData[i].caseNum &&
              row.name === this.tableData[i].name &&
              row.age === this.tableData[i].age
            ) {
              rowspan++;
            } else {
              break;
            }
          }
          return [rowspan, 1];
        }
      }
    },
  },
  created() {
    this.rowspanMethod(this.tableData);
  },
};
</script>

<style lang="less" scoped>
.project-detail {
  background: #f5f5f5;
  min-height: auto;
  padding-bottom: 0.2rem;
  .table {
    width: 600px;
    display: table;
    background: #fff;
    border-collapse: collapse;
    tr {
      display: table-row;
      td {
        border: 1px solid;
        text-align: center;
        display: table-cell;
        padding: 8px 6px;
        white-space: nowrap;
        color: #1c3375;
        font-size: 13px;
        &.right {
          text-align: right;
        }
      }
      &.head {
        font-weight: bold;
        background: #fef6ea;
        color: #1c3375;
        font-size: 13px;
        td {
          border: 1px solid transparent;
        }
      }
    }
  }
}
</style>

el-table 主要就是使用了 :span-method="objectSpanMethod" 不明白自己打印就知道都是什么东西了 然后按照你需求调整一下 表格列prop记得写对 不然不生效

table标签 主要就是使用了rowspan属性 然后结合v-if 隐藏合并的 所以需要把你表格数据都过一遍 添加上标识

我写的时候还发现需要写序号 不然这数据就少了 但是不知道怎么回事啊啊 有好心人可以告诉我也ok

方法谁有更好的方法可以自己整理 哥们水平就是个百度cxy 每天复制粘贴