Skip to content

如何实现自动合并表格相同数据的功能

  1. VUE代码如下
vue
<template>
  <table class="combine-table" v-if="combineData.length > 0">
    <tbody>
    <tr class="combine-header">
      <td class="combine-header-item1">标题1</td>
      <td class="combine-header-item2">标题2</td>
      <td class="combine-header-item3">标题3</td>
      <td class="combine-header-item4">标题4</td>
      <td class="combine-header-item5">标题5</td>
      <td class="combine-header-item6">标题6</td>
      <td class="combine-header-item7">标题7</td>
    </tr>
    <tr v-for="(item,index) in list" class="combine-body" :key="index" :id="index">
      <template v-for="(e,i) in item">
        <td v-if="combineData[i][index] !== 0"
            :class="classFunc(i)"
            :rowSpan="combineData[i][index]"
            :key="indexFunc(index)"
            :id="indexFunc(index)">
          <span class="combine-body-text">{{ e }}</span>
        </td>
      </template>
    </tr>
    </tbody>
  </table>

</template>

<script setup lang="ts">

import {ref, watchEffect} from 'vue';

const classFunc = (i: number) => 'combine-body-item' + (i + 1)
const indexFunc = (i: number) => i + "_" + i
const initialList = [
  [
    "3000009",
    "3",
    "01/08",
    "2021/10/20",
    "B/J",
    "1",
    "1",
  ],
  [
    "3000009",
    "3",
    "01/08",
    "2021/03/02",
    "XH",
    "1",
    "2",
  ],
  [
    "3000009",
    "3",
    "01/08",
    "2021/10/15",
    "6SD0G",
    "1",
    "3",
  ],
  ["1000025", "33", "03/01", "2021/03/11", "JZ0B", "13", "4"],
  ["1000026", "33", "03/01", "2021/03/11", "JZ0B", "13", "4"],
  ["1000027", "33", "03/01", "2021/03/11", "JZ0B", "13", "4"],
];

const list = ref<string[][]>(initialList)
const combineData = ref<number[][]>([])
const maxCombineColumn = ref<number>(initialList.length > 0 ? initialList[0].length - 1 : 0)
const limitCombineColumn = ref<number>(initialList.length > 0 ? initialList[0].length - 1 : 0)
watchEffect(() => {
  /**
   * 合并表格
   */
  const combineTableFun = (list: string[][]) => {
    const tableData = list;
    const result: number[][] = [];
    for (let i = 0; i <= maxCombineColumn.value; i++) {
      const combineData: number[] = [];
      if (i > limitCombineColumn.value) {
        for (let j = 0; j < tableData.length; j++) {
          combineData.push(1);
        }
        result.push(combineData)
        continue;
      }

      let temp, count = 1;
      /** 填充内容的方法 **/
      const tablePush = (count: number) => {
        for (let j = 0; j < count; j++) {
          if (j == 0) {
            combineData.push(count);
          } else {
            combineData.push(0);
          }
        }
      };
      for (let j = 0; j < tableData.length; j++) {
        if (j == 0) {
          temp = tableData[j][i];
        } else {
          if (tableData[j][i] == temp) {
            count++;
            if (j == tableData.length - 1) {
              tablePush(count);
            }
          } else {
            tablePush(count);
            temp = tableData[j][i];
            count = 1;
            if (j == tableData.length - 1) {
              tablePush(count);
            }
          }
        }
      }
      result.push(combineData);
    }
    return result;
  };
  // limitCombineColumn.value = 2
  combineData.value = combineTableFun(list.value);
})
</script>

<style lang="scss" scoped>
.combine-table {
  width: 1086px;
  max-height: 621px;
  overflow-y: auto;
  border-collapse: collapse;
}

.combine-table, .combine-table tr td {
  border: 1px solid rgba(0, 33, 87, 1);
}

.combine-header {
  width: 100%;
  height: 32px;
  background-color: rgba(0, 41, 111, 1);
  text-align: center;
}

.combine-header-item1,
.combine-header-item2,
.combine-header-item3,
.combine-header-item4,
.combine-header-item5,
.combine-header-item6,
.combine-header-item7 {
  font-size: 12px;
  font-family: Microsoft YaHei, serif;
  font-weight: 400;
  color: #7dd9ff;
  line-height: 32px;
  border-spacing: 0;
  border: 1px solid rgba(0, 33, 87, 1);
}

.combine-header-item1,
.combine-body-item1 {
  width: 134px;
}

.combine-header-item2,
.combine-body-item2 {
  width: 160px;
}

.combine-header-item3,
.combine-body-item3 {
  width: 110px;
}

.combine-header-item4,
.combine-body-item4 {
  width: 113px;
}

.combine-header-item5,
.combine-body-item5 {
  width: 332px;
}

.combine-header-item6,
.combine-body-item6 {
  width: 136px;
}

.combine-header-item7,
.combine-body-item7 {
  width: 108px;
}

.combine-body {
  width: 100%;
  text-align: center;
}

.combine-body-item1,
.combine-body-item2,
.combine-body-item3,
.combine-body-item4,
.combine-body-item5,
.combine-body-item6,
.combine-body-item7 {
  min-height: 32px;
}

.combine-body-item1,
.combine-body-item2,
.combine-body-item3 {
  background-color: rgba(0, 49, 150, 1);
}

.combine-body-item4,
.combine-body-item5,
.combine-body-item6,
.combine-body-item7 {
  background-color: rgba(12, 37, 128, 1);
}

.combine-body-text {
  font-size: 12px;
  font-family: Microsoft YaHei, serif;
  font-weight: 400;
  color: #b7eaff;
  line-height: 32px;
}

</style>
<template>
  <table class="combine-table" v-if="combineData.length > 0">
    <tbody>
    <tr class="combine-header">
      <td class="combine-header-item1">标题1</td>
      <td class="combine-header-item2">标题2</td>
      <td class="combine-header-item3">标题3</td>
      <td class="combine-header-item4">标题4</td>
      <td class="combine-header-item5">标题5</td>
      <td class="combine-header-item6">标题6</td>
      <td class="combine-header-item7">标题7</td>
    </tr>
    <tr v-for="(item,index) in list" class="combine-body" :key="index" :id="index">
      <template v-for="(e,i) in item">
        <td v-if="combineData[i][index] !== 0"
            :class="classFunc(i)"
            :rowSpan="combineData[i][index]"
            :key="indexFunc(index)"
            :id="indexFunc(index)">
          <span class="combine-body-text">{{ e }}</span>
        </td>
      </template>
    </tr>
    </tbody>
  </table>

</template>

<script setup lang="ts">

import {ref, watchEffect} from 'vue';

const classFunc = (i: number) => 'combine-body-item' + (i + 1)
const indexFunc = (i: number) => i + "_" + i
const initialList = [
  [
    "3000009",
    "3",
    "01/08",
    "2021/10/20",
    "B/J",
    "1",
    "1",
  ],
  [
    "3000009",
    "3",
    "01/08",
    "2021/03/02",
    "XH",
    "1",
    "2",
  ],
  [
    "3000009",
    "3",
    "01/08",
    "2021/10/15",
    "6SD0G",
    "1",
    "3",
  ],
  ["1000025", "33", "03/01", "2021/03/11", "JZ0B", "13", "4"],
  ["1000026", "33", "03/01", "2021/03/11", "JZ0B", "13", "4"],
  ["1000027", "33", "03/01", "2021/03/11", "JZ0B", "13", "4"],
];

const list = ref<string[][]>(initialList)
const combineData = ref<number[][]>([])
const maxCombineColumn = ref<number>(initialList.length > 0 ? initialList[0].length - 1 : 0)
const limitCombineColumn = ref<number>(initialList.length > 0 ? initialList[0].length - 1 : 0)
watchEffect(() => {
  /**
   * 合并表格
   */
  const combineTableFun = (list: string[][]) => {
    const tableData = list;
    const result: number[][] = [];
    for (let i = 0; i <= maxCombineColumn.value; i++) {
      const combineData: number[] = [];
      if (i > limitCombineColumn.value) {
        for (let j = 0; j < tableData.length; j++) {
          combineData.push(1);
        }
        result.push(combineData)
        continue;
      }

      let temp, count = 1;
      /** 填充内容的方法 **/
      const tablePush = (count: number) => {
        for (let j = 0; j < count; j++) {
          if (j == 0) {
            combineData.push(count);
          } else {
            combineData.push(0);
          }
        }
      };
      for (let j = 0; j < tableData.length; j++) {
        if (j == 0) {
          temp = tableData[j][i];
        } else {
          if (tableData[j][i] == temp) {
            count++;
            if (j == tableData.length - 1) {
              tablePush(count);
            }
          } else {
            tablePush(count);
            temp = tableData[j][i];
            count = 1;
            if (j == tableData.length - 1) {
              tablePush(count);
            }
          }
        }
      }
      result.push(combineData);
    }
    return result;
  };
  // limitCombineColumn.value = 2
  combineData.value = combineTableFun(list.value);
})
</script>

<style lang="scss" scoped>
.combine-table {
  width: 1086px;
  max-height: 621px;
  overflow-y: auto;
  border-collapse: collapse;
}

.combine-table, .combine-table tr td {
  border: 1px solid rgba(0, 33, 87, 1);
}

.combine-header {
  width: 100%;
  height: 32px;
  background-color: rgba(0, 41, 111, 1);
  text-align: center;
}

.combine-header-item1,
.combine-header-item2,
.combine-header-item3,
.combine-header-item4,
.combine-header-item5,
.combine-header-item6,
.combine-header-item7 {
  font-size: 12px;
  font-family: Microsoft YaHei, serif;
  font-weight: 400;
  color: #7dd9ff;
  line-height: 32px;
  border-spacing: 0;
  border: 1px solid rgba(0, 33, 87, 1);
}

.combine-header-item1,
.combine-body-item1 {
  width: 134px;
}

.combine-header-item2,
.combine-body-item2 {
  width: 160px;
}

.combine-header-item3,
.combine-body-item3 {
  width: 110px;
}

.combine-header-item4,
.combine-body-item4 {
  width: 113px;
}

.combine-header-item5,
.combine-body-item5 {
  width: 332px;
}

.combine-header-item6,
.combine-body-item6 {
  width: 136px;
}

.combine-header-item7,
.combine-body-item7 {
  width: 108px;
}

.combine-body {
  width: 100%;
  text-align: center;
}

.combine-body-item1,
.combine-body-item2,
.combine-body-item3,
.combine-body-item4,
.combine-body-item5,
.combine-body-item6,
.combine-body-item7 {
  min-height: 32px;
}

.combine-body-item1,
.combine-body-item2,
.combine-body-item3 {
  background-color: rgba(0, 49, 150, 1);
}

.combine-body-item4,
.combine-body-item5,
.combine-body-item6,
.combine-body-item7 {
  background-color: rgba(12, 37, 128, 1);
}

.combine-body-text {
  font-size: 12px;
  font-family: Microsoft YaHei, serif;
  font-weight: 400;
  color: #b7eaff;
  line-height: 32px;
}

</style>

最终的效果如下

标题1标题2标题3标题4标题5标题6标题7
3000009301/082021/10/20B/J11
2021/03/02XH2
2021/10/156SD0G3
10000253303/012021/03/11JZ0B134
1000026
1000027