iview table 行列合并

1. 需求

后台获取的数据,前端渲染时,如果同一列相邻的数据相同,则合并成一个单元格。

2 官方示例

设置属性 span-method 可以指定合并行或列的算法。

该方法参数为 4 个对象:

  • row: 当前行
  • column: 当前列
  • rowIndex: 当前行索引
  • columnIndex: 当前列索引

该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。

<template>
    <Table :columns="columns" :data="data" border :span-method="handleSpan"></Table>
</template>
<script>
    export default {
        data () {
            return {
                columns: [
                    {
                        title: 'Date',
                        key: 'date'
                    },
                    {
                        title: 'Name',
                        key: 'name'
                    },
                    {
                        title: 'Age',
                        key: 'age'
                    },
                    {
                        title: 'Address',
                        key: 'address'
                    }
                ],
                data: [
                    {
                        name: 'John Brown',
                        age: 18,
                        address: 'New York No. 1 Lake Park',
                        date: '2016-10-03'
                    },
                    {
                        name: 'Jim Green',
                        age: 24,
                        address: 'London No. 1 Lake Park',
                        date: '2016-10-01'
                    },
                    {
                        name: 'Joe Black',
                        age: 30,
                        address: 'Sydney No. 1 Lake Park',
                        date: '2016-10-02'
                    },
                    {
                        name: 'Jon Snow',
                        age: 26,
                        address: 'Ottawa No. 2 Lake Park',
                        date: '2016-10-04'
                    }
                ]
            }
        },
        methods: {
            handleSpan ({ row, column, rowIndex, columnIndex }) {
                if (rowIndex === 0 && columnIndex === 0) {
                    return [1, 2];
                } else if (rowIndex === 0 && columnIndex === 1) {
                    return  [0, 0];
                }
                if (rowIndex === 2 && columnIndex === 0) {
                    return {
                        rowspan: 2,
                        colspan: 1
                    };
                } else if (rowIndex === 3 && columnIndex === 0) {
                    return {
                        rowspan: 0,
                        colspan: 0
                    };
                }
            }
        }
    }
</script>

注意:合并和被合并的区别,返回值不是[0,0]的,其内容显示在合并后的单元格中。返回值是[0,0]的是被合并的单元格,内容相当于删除

效果图

3 动态合并

handleSpan 实现

/**
 * 合并行或列的算法
 * @param row 当前行
 * @param column 当前列
 * @param rowIndex 当前行索引
 * @param columnIndex 当前列索引
 * @returns {{colspan: (number), rowspan: *}}
 */
handleSpan({ row, column, rowIndex, columnIndex }) {
  // 姓名合并
  if (columnIndex === 0) {
    // 二维数组存储的数据 取出
    const _row = this.nameMerges[rowIndex];
    const _col = _row > 0 ? 1 : 0;
    return {
      rowspan: _row,
      colspan: _col,
    };
  }

  // 地址合并
  if (columnIndex === 2) {
    // 二维数组存储的数据 取出
    const _row = this.addrMerges[rowIndex];
    const _col = _row > 0 ? 1 : 0;
    return {
      rowspan: _row,
      colspan: _col,
    };
  }

  if (columnIndex === 4) {
    // 操作列序号
    // 二维数组存储的数据 取出
    const _row = this.opMerges[rowIndex];
    const _col = _row > 0 ? 1 : 0;
    return {
      rowspan: _row,
      colspan: _col,
    };
  }
},

处理数据

formatData() {
  this.nameMerges = this.getMerges(this.resData, "name");
  this.addrMerges = this.getMerges(this.resData, "address");
  this.opMerges = [...this.nameMerges]; // 复制name的合并信息

  console.log(this.opMerges);
},
/**
 *
 * @param data 数据列表
 * @param key 将要合并的对比字段
 * @returns {*[]}
 */
getMerges(data, key) {

    let spanArr = []
    let pos = 0
    // 遍历数据
    data.forEach((item, index) => {
        // 判断是否是第一项
        if (index === 0) {
            spanArr.push(1)
            pos = 0
        } else {
            // 不是第一项时,就根据标识去存储
            if (data[index][key] === data[index - 1][key]) {
                // 查找到符合条件的数据时每次要把之前存储的数据+1
                spanArr[pos] += 1
                spanArr.push(0)
            } else {
                // 没有符合的数据时,要记住当前的index
                spanArr.push(1)
                pos = index
            }
        }
    })
    return spanArr
},

从后台拿到数据后,先调用下处理数据的方法

this.formatData();

完整代码示例

<template>
  <Table
    class="border-table"
    :columns="columns"
    :data="resData"
    border
    :span-method="handleSpan"
  >
    <!-- 操作 -->
    <template slot="xm" slot-scope="{ row, index }">
      <a href="">{{ row.name }}</a>
    </template>
    <!-- 操作 -->
    <template slot="action" slot-scope="{ row, index }">
      <div class="tableBtnBox enniu">
        <div class="tableBtn">
          <Button class="cz_btn" type="success" size="small">查看详情</Button>
        </div>
      </div>
    </template>
  </Table>
</template>
<script>
export default {
  data() {
    return {
      columns: [
        {
          title: "Name",
          // key: "name",
          slot: "xm",
        },
        {
          title: "Age",
          key: "age",
        },
        {
          title: "Address",
          key: "address",
        },
        {
          title: "Desc",
          key: "desc",
        },
        {
          title: "操作",
          align: "center",
          slot: "action",
        },
      ],
      resData: [
        {
          "id": 1,
          "name": "John Doe",
          "age": 32,
          "address": "202 Main Street, New York, NY",
          "desc": "Data engineer"
        },
        {
          "id": 2,
          "name": "Lisa Wang",
          "age": 28,
          "address": "99 Long Road, Shanghai, CN",
          "desc": "Product manager"
        },
        {
          "id": 3,
          "name": "Jane Smith",
          "age": 35,
          "address": "99 Long Road, Shanghai, CN",
          "desc": "Software architect"
        },
        {
          "id": 4,
          "name": "Jane Smith",
          "age": 29,
          "address": "51 South Avenue, Miami, FL",
          "desc": "UI designer"
        },
        {
          "id": 5,
          "name": "Tom Brown",
          "age": 29,
          "address": "1675 Park Avenue, Paris, FR",
          "desc": "Backend developer"
        },
        {
          "id": 6,
          "name": "Alice Chen",
          "age": 30,
          "address": "20 Surry Street, London, UK",
          "desc": "DevOps engineer"
        }
      ],
      nameMerges: [],
      addrMerges: [],
      opMerges: [],
    };
  },
  methods: {
    /**
     * 合并行或列的算法
     * @param row 当前行
     * @param column 当前列
     * @param rowIndex 当前行索引
     * @param columnIndex 当前列索引
     * @returns {{colspan: (number), rowspan: *}}
     */
    handleSpan({ row, column, rowIndex, columnIndex }) {
      // 姓名合并
      if (columnIndex === 0) {
        // 二维数组存储的数据 取出
        const _row = this.nameMerges[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          rowspan: _row,
          colspan: _col,
        };
      }

      // 地址合并
      if (columnIndex === 2) {
        // 二维数组存储的数据 取出
        const _row = this.addrMerges[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          rowspan: _row,
          colspan: _col,
        };
      }

      if (columnIndex === 4) {
        // 操作列序号
        // 二维数组存储的数据 取出
        const _row = this.opMerges[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          rowspan: _row,
          colspan: _col,
        };
      }
    },
    formatData() {
      this.nameMerges = this.getMerges(this.resData, "name");
      this.addrMerges = this.getMerges(this.resData, "address");
      this.opMerges = [...this.nameMerges]; // 复制name的合并信息

      console.log(this.opMerges);
    },
    /**
     *
     * @param data 数据列表
     * @param key 将要合并的对比字段
     * @returns {*[]}
     */
    getMerges(data, key) {
      // 页面展示的数据,不一定是全部的数据,所以每次都清空之前存储的 保证遍历的数据是最新的数据。以免造成数据渲染混乱
      let spanArr = [];
      let pos = 0;
      // 遍历数据
      data.forEach((item, index) => {
        // 判断是否是第一项
        if (index === 0) {
          spanArr.push(1);
          pos = 0;
        } else {
          // 不是第一项时,就根据标识去存储
          if (data[index][key] === data[index - 1][key]) {
            // 查找到符合条件的数据时每次要把之前存储的数据+1
            spanArr[pos] += 1;
            spanArr.push(0);
          } else {
            // 没有符合的数据时,要记住当前的index
            spanArr.push(1);
            pos = index;
          }
        }
      });
      return spanArr;
    },
  },
  mounted() {
    this.formatData();
  },
};
</script>
<style scoped>

</style>

效果图


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!