el-table相同数据行单元格合并

本文介绍了如何在使用Vue.js和ElementUI的项目中,通过计算合并行号和编写合并方法,实现el-table中相同数据行的单元格合并。详细步骤包括绘制表格、计算并存储合并行号、编写行号合并方法。在组件mounted阶段计算合并行号数组,并通过span-method处理行合并。作者希望有更优的实现方案,并提供了简化后的完整代码示例。

背景

项目中列表第一列是名称,需要实现的效果是相同名称的行合并,如图所示:合并示例

实现步骤

1.绘制el-table

按照常规的写法绘制一个表格,根据官方文档 element-ui 介绍编写表格合并规则方法。
代码示例中的 span-method

    <el-table v-loading="listLoading" :data="list" :span-method="objectSpanMethod" >
      <el-table-column prop="name" label="name" width="120"></el-table-column>
      <el-table-column prop="Title" label="Title" width="120"></el-table-column>
      <el-table-column prop="Pageviews" label="Pageviews" width="120" align="center"> </el-table-column>
      <el-table-column prop="Status" label="Status" width="110"> </el-table-column>
      <el-table-column prop="created_at" label="Display_time" width="200"></el-table-column>
    </el-table>

2.编写合并方法

2.1 计算合并的行号

  1. 在data中定义全局变量indexArray 存储所有合并的行号;
  2. 通过传入行号及该行名称,遍及计算该行下方数据相同的行数
  methods: {
    getRows(rowIndex, name) {
      let count = 0
      for (let i = rowIndex; i < this.list.length; i++) {
        if (this.list[i].name === name) {
          count++
        } else {
          break
        }
      }
      return count
    }
  }

2.2 计算合并行号数组indexArray

在组件mounted构建时计算合并行号数组indexArray

  let count = 0
  for (let rowIndex = 0; rowIndex < this.list.length; ) {
    this.indexArray.push(rowIndex)
    count = this.getRows(rowIndex, this.list[rowIndex].name)
    rowIndex += count
  }

其中,list是整个table的数据来源

2.3 编写行号合并方法

当该行的rowIndex在合并行号数组中时返回合并行数据,否则返回空。

  methods: {
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        let rowCount = 0
        if (this.indexArray.includes(rowIndex)) {
          rowCount = this.getRows(rowIndex, row.name)
          return {
            rowspan: rowCount,
            colspan: 1
          }
        } else {
          return {
            rowspan: 0,
            colspan: 0
          }
        }
      }
    }
  }

(作者碎碎念)官网也是通过行号来控制合并,我一开始总是想用列表的属性值判断,但是每每都会陷入无限循环的困境,这种实现方式不算好,如果大佬有更好的实现方式欢迎评论,小弟不胜感激!!!

3.全部代码

项目代码不方便公开,这是我简化后的一个完整的实现代码:

<template>
  <div class="app-container">
    <el-table :data="list" :span-method="objectSpanMethod">
      <el-table-column prop="name" label="name" width="120" />
      <el-table-column prop="title" label="Title" width="120" />
      <el-table-column prop="pageviews" label="Pageviews" width="120" />
      <el-table-column prop="status" label="Status" width="110" />
      <el-table-column prop="display_time" label="Display_time" width="200" />
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [
        {
          name: '张三',
          title: '文本一',
          status: 'published',
          display_time: '2023-07-14',
          pageviews: 200
        },
        {
          name: '李四',
          title: '文本二',
          status: 'published',
          display_time: '2023-07-14',
          pageviews: 200
        },
        {
          name: '李四',
          title: '文本三',
          status: 'published',
          display_time: '2023-07-14',
          pageviews: 200
        },
        {
          name: '王五',
          title: '文本四',
          status: 'published',
          display_time: '2023-07-14',
          pageviews: 200
        },
        {
          name: '王五',
          title: '文本五',
          status: 'published',
          display_time: '2023-07-14',
          pageviews: 200
        },
        {
          name: '王五',
          title: '文本六',
          status: 'published',
          display_time: '2023-07-14',
          pageviews: 200
        }
      ],
      indexArray: []
    }
  },
  mounted() {
    let count = 0
    for (let rowIndex = 0; rowIndex < this.list.length; ) {
      this.indexArray.push(rowIndex)
      count = this.getRows(rowIndex, this.list[rowIndex].name)
      rowIndex += count
    }
  },
  methods: {
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        let rowCount = 0
        if (this.indexArray.includes(rowIndex)) {
          rowCount = this.getRows(rowIndex, row.name)
          return {
            rowspan: rowCount,
            colspan: 1
          }
        } else {
          return {
            rowspan: 0,
            colspan: 0
          }
        }
      }
    },
    getRows(rowIndex, name) {
      let count = 0
      for (let i = rowIndex; i < this.list.length; i++) {
        if (this.list[i].name === name) {
          count++
        } else {
          break
        }
      }
      return count
    }
  }
}
</script>
### 使用Element UI的`el-table`实现合并和折叠单元格 #### 合并单元格 为了在 `el-table` 中实现单元格合并的功能,可以利用 `:span-method` 属性。此属性允许定义一个函数来自定义列跨距。下面是一个简单的例子展示如何通过设置该属性来达到目的: ```html <template> <div> <el-table :data="tableData" border style="width: 100%" :span-method="objectSpanMethod"> <!-- 假设有三列 --> <el-table-column prop="date" label="日期"></el-table-column> <el-table-column prop="name" label="姓名"></el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </div> </template> <script> export default { data() { return { tableData: [ { date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles' }, { date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles' }, // 这里有重复的数据用于演示合并 ... ] }; }, methods: { objectSpanMethod({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0 || columnIndex === 1) { // 对前两列应用合并逻辑 const _row = this.tableData.filter(item => item.date === row.date && item.name === row.name).length; const _col = _row > 1 ? 1 : 0; return [_row, _col]; } } } }; </script> ``` 上述代码片段展示了当遇到相同日期和名字时会自动将这些记录所在的单元格纵向合并[^1]。 #### 折叠单元格 对于想要控制某些特定情况下折叠或展开某一的需求,则可以通过监听事件以及手动调用API接口的方式来完成。这里给出了一种解决方案,在加载新数据之后让所有的子项都处于收起状态: ```html <template> <div> <el-button type="primary" @click="loadData">刷新表格并关闭所有展开</el-button> <el-table :data="tableData" ref="multipleTable" :row-key="getRowKeys" @expand-change="handleExpandChange"> <!-- 列定义省略... --> </el-table> </div> </template> <script> export default { data() { return { tableData: [], // 初始化为空列表 expandedRowKeys: [] // 记录当前已扩展的key集合 }; }, methods: { getRowKeys(row) { return row.id; // 设置每一唯一标识符作为键值 }, handleExpandChange(row, expandedRows) { let key = this.getRowKeys(row); if(expandedRows.length===0){ this.expandedRowKeys.splice(this.expandedRowKeys.indexOf(key), 1); }else{ this.expandedRowKeys.push(key); } }, loadData(){ // 模拟异步获取新的数据... setTimeout(() => { this.tableData = newDataList.map((item,index)=>({...item,id:index})); // 给每条记录加上唯一的id字段 // 关闭之前已经打开的所有 this.$refs.multipleTable.store.states.expandRows.forEach(row=>{ this.$refs.multipleTable.toggleRowExpansion(row,false); }); this.expandedRowKeys=[];// 清空缓存中的expanded keys }, 1000); } } } </script> ``` 这段脚本实现了点击按钮后重新请求服务器端的新鲜数据,并且确保每次更新完毕都会把先前被用户手工展开了的内容再次收缩起来[^2]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值