vue+element 表格table行row动态合并==>组件封装

978 阅读5分钟

本文使用的技术栈是vue2+element

1、需求一:将所有内容相同且相邻的行单元格合并

image.png

1、需求分析

  • 我们判断行的合并首先要从第一列开始判断,从前往后判断,其列上相邻的表格内容是否相同
  • 如果相同即进行合并,否则(前面列的表格都不相同,也没必要继续往下判断了)都就不会往下判断(即再判断第二列,第三列.....)

image.png

思路:首先使用getSpanArray方法创建spanArr数组,spanArr数组是一个二维数组, 在这里我使用了element里的:span-method="objectSpanMethod"方法,objectSpanMethod会根据spanArr数组进行合并处理 例子如图所示:

image.png

组件TableMerge

<template>
  <div style="padding-top: 20px">
    <el-table
      :data="tableData"
      :span-method="objectSpanMethod"
      style="width: 100%"
    >
      <el-table-column
        v-for="column in columns"
        :key="column.prop"
        :prop="column.prop"
        :label="column.label"
        :width="column.width"
      ></el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  props: {
    tableData: {
      type: Array,
      default: () => [],
    },
    columns: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      spanArr: [],
    };
  },
  mounted() {
    this.getSpanArray(this.tableData,this.columns);
  },
  methods: {
    getSpanArray(data, columns) {
    // 每次进入方法都先将spanArr数组清空,防止数据多次往数组内推入,导致数据叠加在一起
    this.spanArr = []
      // 1.首先将每一列的字段名都提取出来(便于接下来进行判断)
      const arr = columns.map((e) => e.prop);
      // 2.创建数组nameObj,此数组用来保存正在循环的行数
      const nameObj = new Array(arr.length).fill(0);
      for (let i = 0; i < data.length; i++) {
      //3.遍历循环表格数组,判断如果是表格的第一行,那么就进行保底操作根据arr的长度生成对应的个数,并将每个数值做成1(保底操作,因为只要表格有数据,那么第一行肯定至少占单元格1,因此保底)
        if (i === 0) {
          this.spanArr[0] = new Array(arr.length).fill(1);
          // 记录当前循环的行
          nameObj[0] = 0;
        } else {
        //4.创建newRow数组,此数组即每行单元格占的个数,即spanArr二维数组的每一项数组
          let newRow = [];
          5.创建isEqual变量作为开关
          let isEqual = true;
          6.遍历上面创建的字段数组arr,因为判断是需要与当前项的上一项判断内容是否相等才会进行合并,所以在上一步加了个开关,默认一直为true的状态,一旦当前项的上一项判断内容不同直接把开关关闭,相当于结束了循环里的操作
          for (let j = 0; j < arr.length; j++) {
            if (data[i][arr[j]] === data[i - 1][arr[j]] && isEqual) {
              this.spanArr[nameObj[j]][j] += 1;
              newRow.push(0);
            } else {
            // 一旦当前项的上一项判断内容不同直接把开关关闭,相当于结束了循环里的操作
              isEqual = false;
              newRow.push(1);
              nameObj[j] = i;
            }
          }
          // 7.最后spanArr数组把处理好的newRow数组存起来即可
          this.spanArr.push(newRow);
        }
      }
    },
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
     // 此处是给每一项进行了合并操作
        const _row = this.spanArr[rowIndex][columnIndex];
        const _col = _row > 0 ? 1 : 0;
        return { rowspan: _row, colspan: _col };
    },
  },
};
</script>

组件接受两个数据,即tableData表格数据 + columns表格列的循环与其取值 代码的相关解释写在代码块里了

使用组件TableMerge

<template>
  <div>
    <TableMerge
      :tableData="tableData"
      :columns="columns"
    ></TableMerge>
  </div>
</template>

<script>
import TableMerge from "@/components/TableMerge.vue";
export default {
  name: "ProjectWebHomeView",
  components: {
    TableMerge,
  },
  data() {
    return {
      tableData: [
        {
          date: "2016-05-02",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
          age:'18'
        },
        {
          date: "2016-05-02",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1517 弄",
          age:'18'

        },
        {
          date: "2016-05-02",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1517 弄",
          age:'19'

        },
        {
          date: "2016-05-03",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1516 弄",
          age:'18'
        },
        {
          date: "2016-05-03",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1512弄",
          age:'18'
        },        {
          date: "2016-05-03",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1518弄",
          age:'19'
        },
      ],
      columns:[
        {
          prop:'date',
          label:'日期',
          width:'200'
        },
        {
          prop:'name',
          label:'姓名',
          width:'140'
        },
        {
          prop:'address',
          label:'地址',
          width:'240'
        },
        {
          prop:'age',
          label:'年龄',
          width:'200'
        }
      ]
    };
  },

  mounted() {},

  methods: {},
};
</script>

<style lang="scss" scoped></style>

2、需求二:优化==>只针对与指定列进行单元格合并

需求一的操作是针对了所有列表格进行了合并操作,但我们有时候需要只合并某些列,那么我们继续要对代码再次进行优化,效果如下:下图只针对了第一列进行合并 image.png

  • 下面是完整代码
  • 组件多添加了mergeTable参数,来判断表格是否进行表格合并操作
<template>
  <div style="padding-top: 20px">
    <el-table
      :data="tableData"
      :span-method="objectSpanMethod"
      style="width: 100%"
    >
      <el-table-column
        v-for="column in columns"
        :key="column.prop"
        :prop="column.prop"
        :label="column.label"
        :width="column.width"
      ></el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  props: {
    tableData: {
      type: Array,
      default: () => [],
    },
    columns: {
      type: Array,
      default: () => [],
    },
    mergeTable: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      spanArr: [],
    };
  },
  mounted() {
    this.getSpanArray(this.tableData, this.columns);
  },
  methods: {
    getSpanArray(data, columns) {
      const arr = columns.map((e) => e.prop);
      const nameObj = new Array(arr.length).fill(0);
      for (let i = 0; i < data.length; i++) {
        if (i === 0) {
          this.spanArr[0] = new Array(arr.length).fill(1);
          nameObj[0] = 0;
        } else {
          let newRow = [];
          let isEqual = true;
          for (let j = 0; j < arr.length; j++) {
            if (columns[j].isMerge === false) {
              isEqual = false;
              newRow.push(1);
              nameObj[j] = i;
            }
            if (data[i][arr[j]] === data[i - 1][arr[j]] && isEqual) {
              this.spanArr[nameObj[j]][j] += 1;
              newRow.push(0);
            } else {
              isEqual = false;
              newRow.push(1);
              nameObj[j] = i;
            }
          }
          this.spanArr.push(newRow);
        }
      }
    },
    objectSpanMethod({rowIndex, columnIndex }) {
      if (this.mergeTable) {
        const _row = this.spanArr[rowIndex][columnIndex];
        const _col = _row > 0 ? 1 : 0;
        return { rowspan: _row, colspan: _col };
      } else {
        return { rowspan: 1, colspan: 1 };
      }
    },
  },
};
</script>
  • 组件使用
  • 再想组件传递需要传递mergeTable为true才会进行合并表格操作
  • 传递的columns数组对象的每项对象,需要新添加一个isMerge的属性,true则是对此列进行合并表格的操作,false则不进行合并
<template>
  <div>
    <TableMerge
      :tableData="tableData"
      :columns="columns"
      :mergeTable="true"
    ></TableMerge>
  </div>
</template>

<script>
import TableMerge from "@/components/tableCellTip.vue";
export default {
  name: "ProjectWebHomeView",
  components: {
    TableMerge,
  },
  data() {
    return {
      tableData: [
        {
          date: "2016-05-02",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
          age:'18'
        },
        {
          date: "2016-05-02",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1517 弄",
          age:'18'

        },
        {
          date: "2016-05-02",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1517 弄",
          age:'19'

        },
        {
          date: "2016-05-03",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1516 弄",
          age:'18'
        },
        {
          date: "2016-05-03",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1512弄",
          age:'18'
        },        {
          date: "2016-05-03",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1518弄",
          age:'19'
        },
      ],
      columns:[
        {
          prop:'date',
          label:'日期',
          width:'200',
          isMerge:true
        },
        {
          prop:'name',
          label:'姓名',
          width:'140',
          isMerge:false

        },
        {
          prop:'address',
          label:'地址',
          width:'240',
          isMerge:false

        },
        {
          prop:'age',
          label:'年龄',
          width:'200',
          isMerge:false

        }
      ]
    };
  },

  mounted() {},

  methods: {},
};
</script>

<style lang="scss" scoped></style>


完结👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌