el-table根据data动态合并列

1,056 阅读1分钟

Element UI官方文档中有说明使用span-method去实现el-table的列合并功能,但是有时候我们需要根据接口数据动态的设置列的合并,同样是使用span-method实现,只是需要自己处理好合并逻辑。

实现代码如下

<template>
  <div class="container">
    <el-table
      :data="tableData"
      :span-method="objectSpanMethod"
      border
      style="width: 100%"
    >
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column prop="sex" label="性别" />
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: []
    };
  },
  mounted() {
    this.getData();
  },
  methods: {
    /** 模拟从接口获取动态数据 */
    getData() {
      setTimeout(() => {
        const data = [
          {
            name: '龙一',
            age: 21,
            sex: '男'
          },
          {
            name: '王二',
            age: 22,
            sex: '女'
          },
          {
            name: '张三',
            age: 21,
            sex: '女'
          },
          {
            name: '李四',
            age: 21,
            sex: '男'
          },
          {
            name: '麻五',
            age: 21,
            sex: '男'
          },
          {
            name: '老六',
            age: 22,
            sex: '男'
          },
          {
            name: '小七',
            age: 22,
            sex: '男'
          },
          {
            name: '阿八',
            age: 22,
            sex: '女'
          },
          {
            name: '九九',
            age: 22,
            sex: '男'
          }
        ];
        this.tableData = this.handleTableData(data, 'sex');
      }, 100);
    },
    /**
     * @desc 处理数据-计算合并的行存储起来
     * @param  {Array} data 接口返回的数据集合
     * @param  {String} prop 需要合并的列
     * @returns {Array} 处理之后的数据集合
     */
    handleTableData(data, prop) {
      const tableData = (data || []).map((ele) => {
        if (prop) {
          // $merge用来记录合并信息
          if (!ele.$merge) {
            ele.$merge = {};
          }
        }
        return ele;
      });

      let pos = 0; // 用来记录合并起始行的下表
      const len = tableData.length;
      for (let i = 0; i < len; i++) {
        const item = tableData[i];
        if (i === 0) {
          item.$merge[prop] = 1;
          pos = 0;
        }
        if (i !== 0) {
          // 判断当前行的值与上一行的值是否相等
          const flag = item[prop] === tableData[i - 1][prop];
          if (flag) {
            // 如果当前行的值与上一行的值相等,则当在当前行数据中加入$merge信息记录当前行是需要合并的
            item.$merge[prop] = 0;
            tableData[pos].$merge[prop] = tableData[pos].$merge[prop] + 1; // 将记录合并起始行的数据中的合并行数+1,后续处理合并时就可以直接知道当前要合并几行数据
          } else {
            // 如果是不相等,则记录当前行是不合并
            item.$merge[prop] = 1;
            // 并且将合并起始行位置设置为当前下标
            pos = i;
          }
        }
      }
      return tableData;
    },

    /** 处理列合并 */
    objectSpanMethod(params) {
      const { row, column } = params;
      const { property } = column;
      if (property === 'sex') {
        // 当当前列是需要合并的列时,从之前存储合并信息的$merge找到当前列的合并信息,进行数据合并
        return {
          rowspan: row.$merge[property], // 设置当前单元格占据几行
          colspan: row.$merge[property] ? 1 : 0 // 1 代表显示当前单元格,0代表不显示
        };
      }
    }
  }
};
</script>

<style scoped>
.container {
  background-color: #fff;
  padding: 8px;
}
</style>

<template>
  <div class="container">
    <el-table
      :data="tableData"
      :span-method="objectSpanMethod"
      border
      style="width: 100%"
    >
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column prop="sex" label="性别" />
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: []
    };
  },
  mounted() {
    this.getData();
  },
  methods: {
    /** 模拟从接口获取动态数据 */
    getData() {
      setTimeout(() => {
        const data = [
          {
            name: '龙一',
            age: 21,
            sex: '男'
          },
          {
            name: '王二',
            age: 22,
            sex: '女'
          },
          {
            name: '张三',
            age: 21,
            sex: '女'
          },
          {
            name: '李四',
            age: 21,
            sex: '男'
          },
          {
            name: '麻五',
            age: 21,
            sex: '男'
          },
          {
            name: '老六',
            age: 22,
            sex: '男'
          },
          {
            name: '小七',
            age: 22,
            sex: '男'
          },
          {
            name: '阿八',
            age: 22,
            sex: '女'
          },
          {
            name: '九九',
            age: 22,
            sex: '男'
          }
        ];
        this.tableData = this.handleTableData(data, 'sex');
      }, 100);
    },
    /**
     * @desc 处理数据-计算合并的行存储起来
     * @param  {Array} data 接口返回的数据集合
     * @param  {String} prop 需要合并的列
     * @returns {Array} 处理之后的数据集合
     */
    handleTableData(data, prop) {
      const tableData = (data || []).map((ele) => {
        if (prop) {
          // $merge用来记录合并信息
          if (!ele.$merge) {
            ele.$merge = {};
          }
        }
        return ele;
      });

      let pos = 0; // 用来记录合并起始行的下表
      const len = tableData.length;
      for (let i = 0; i < len; i++) {
        const item = tableData[i];
        if (i === 0) {
          item.$merge[prop] = 1;
          pos = 0;
        }
        if (i !== 0) {
          // 判断当前行的值与上一行的值是否相等
          const flag = item[prop] === tableData[i - 1][prop];
          if (flag) {
            // 如果当前行的值与上一行的值相等,则当在当前行数据中加入$merge信息记录当前行是需要合并的
            item.$merge[prop] = 0;
            tableData[pos].$merge[prop] = tableData[pos].$merge[prop] + 1; // 将记录合并起始行的数据中的合并行数+1,后续处理合并时就可以直接知道当前要合并几行数据
          } else {
            // 如果是不相等,则记录当前行是不合并
            item.$merge[prop] = 1;
            // 并且将合并起始行位置设置为当前下标
            pos = i;
          }
        }
      }
      return tableData;
    },

    /** 处理列合并 */
    objectSpanMethod(params) {
      const { row, column } = params;
      const { property } = column;
      if (property === 'sex') {
        // 当当前列是需要合并的列时,从之前存储合并信息的$merge找到当前列的合并信息,进行数据合并
        return {
          rowspan: row.$merge[property], // 设置当前单元格占据几行
          colspan: row.$merge[property] ? 1 : 0 // 1 代表显示当前单元格,0代表不显示
        };
      }
    }
  }
};
</script>

<style scoped>
.container {
  background-color: #fff;
  padding: 8px;
}
</style>

效果图

c94ee397b52f7f688131241c9e922cb.jpg