使用element-ui的el-table和el-pagination标签实现表格分页功能以及解决遇到的暂无数据的bug

博主需要在项目中需要使用el-tableel-pagination标签实现表格分页功能,方法如下:

  1. el-table标签的data属性是显示的数据,绑定为showTable计算属性
<el-table
      :data="showTable"
      :header-cell-style="{background:'#eef1f6',color:'#606266'}"
      highlight-current-row
      height="400"
      style="border:1px solid #dfe6ec;"
      v-loading="loading"
    >
      <el-table-column 
      type="index" 
      label="序号" 
      width="60" 
      align="center"
      ></el-table-column>
      ...
</el-table>
  1. el-pagination标签current-change事件会在当前页改变时被触发,绑定为handleCurrentChange方法,page-size属性绑定的是每页显示条目个数
<el-col :span="24" class="toolbar" style="text-align:center">
      <el-pagination
        @current-change="handleCurrentChange"
        layout="total, prev, pager, next"
        :page-size="pagesize"
        :total="this.filterAutomobileInfs.length"
      ></el-pagination>
</el-col>
  1. 设置初始化数据并编写事件触发的方法
export default {
  data() {
    return {
      ...
      pagesize: 10, //设置每页显示条目个数为10
      currentPage: 1, //设置当前页默认为1
      filterAutomobileInfs: [], //分页前的数据
      ...
    }
  },
  computed: {
  //showTable计算属性通过slice方法计算表格当前应显示的数据
    showTable() {
      return this.filterAutomobileInfs.slice(
        (this.currentPage - 1) * this.pagesize,
        this.currentPage * this.pagesize
      );
    }
  },
  methods: {
    //设置当前页为点击页
   	handleCurrentChange(currentPage) {
      this.currentPage = currentPage;
    }
  }
}

这样就通过改变表格中绑定的data数据,利用vue数据驱动这一特点实现了表格分页功能。效果如下:

  1. 第1页,显示的数据有10条,分页组件显示共有15条数据
    第一页
  2. 翻到第2页,显示了剩下5条数据
    第二页

博主本以为功能已经成功实现,但是理想很丰满,现实很骨感。博主在测试过程中还是发现了一个有趣的bug:功能有时好使有时不好使(不好使的情况是查询条件无误的时候查询后却没有数据)。遇到这种情况我的表情是这样的:╯﹏╰。根据以往经验,博主首先怀疑是某处的js异步导致的,但是几经折腾却没有什么进展。
于是,博主加强了测试力度,最终得出结论:只有在翻到从第2页开始的之后的页面查询时才会出现无数据的情况。这回答案应该比较明显了,应该是跟页数有关。又考虑到vue的数据驱动特性,终于明白了问题所在:
我们点击第2页之后的页数时会改变当前页数,这个时候点击查询,系统根据查询条件筛选符合条件的数组赋值给定义的filterAutomobileInfs数据项,计算属性通过slice方法筛选表格应显示的数据,而此时currentPage还是改变后的当前页数,所以导致slice方法筛选的数据索引不正确,出现无数据或数据异常的问题。

知道问题原因就好办多了,只需在查询时重新设置当前页数为1就好了,如下:

methods: {
    //查询方法
    searchAutomobile() {
      //currentPage赋值为1
      this.currentPage = 1;
      //筛选方法
      this.filterAutomobile();
    }
    ...
}

这次的问题给我带来的启发很多,我们在遇到问题时一定要多做测试探究问题出现的条件和环境,并且多考虑当前技术的原理,希望借此篇博客与大家共勉吧!

<think>我们正在解决的是:使用span-method合并几十个单元格时出现的bug。 根据之前的讨论,我们已知有两种替代方案(数据预处理CSS视觉合并),但用户现在明确需要使用span-methods方法,并且遇到了合并大量单元格时的bug。 常见bug解决方案: 1. 合并错位:计算合并行数时逻辑错误,导致合并行数对。 2. 性能问题:当数据量大且合并规则复杂时,span-methods方法会被频繁调用(每个单元格都会调用),可能导致页面卡顿。 3. 排序/筛选后合并失效:因为排序后数据的顺序改变,而合并计算依赖于数据顺序。 解决方案: 一、确保合并计算逻辑正确 在`arraySpanMethod`方法中,我们需要返回一个包含两个元素的数组`[rowspan, colspan]`,表示当前单元格占的行数列数。返回`[0,0]`表示显示。 常见做法:预先计算好每个单元格的合并信息,然后在`span-methods`方法中直接返回。 步骤: 1. 在数据中增加字段,标记每个单元格是否应该合并以及合并的行数。 2. 在`arraySpanMethod`方法中,根据当前行列,返回预先计算好的合并信息。 代码示例: ```javascript computed: { // 计算合并配置,这里假设按project_name合并 spanConfig() { const config = []; let pos = 0; // 当前位置 for (let i = 0; i < this.tableData.length; i++) { if (i === 0) { // 第一行,初始为1 config.push(1); pos = 0; } else { // 判断当前行project_name与前一行是否相同 if (this.tableData[i].project_name === this.tableData[i-1].project_name) { config[pos] += 1; // 增加上一个位置的行跨度 config.push(0); // 当前行设置为0,表示显示 } else { config.push(1); pos = i; // 更新位置 } } } return config; } }, methods: { arraySpanMethod({ row, column, rowIndex, columnIndex }) { // 假设只在第一列第二列合并,且合并规则一样(按project_name) if (columnIndex === 0 || columnIndex === 1) { // 返回[rowspan, colspan] // 注意:rowIndex对应spanConfig中的位置 const rowspan = this.spanConfig[rowIndex]; const colspan = rowspan > 0 ? 1 : 0; // 如果rowspan为0,则返回[0,0]表示显示 // 注意:必须返回[0,0]而是[0,1]等,否则会留空 return [rowspan, colspan]; } // 其他列合并 return [1, 1]; } } ``` 二、性能优化 如果数据量很大,每次计算`spanConfig`可能会造成性能问题(比如表格滚动时也会触发span-methods)。因此: 1. 缓存合并配置:在数据变化时才重新计算`spanConfig`(使用computed属性,因为它是响应式的,但注意数据量大时计算可能会慢)。 2. 使用虚拟滚动:可以考虑使用虚拟滚动表格组件(如`el-table`结合`el-table-v2`)来避免渲染大量DOM。 三、排序/筛选后的合并问题 如果表格支持排序或筛选,那么在排序/筛选后,数据顺序会变,需要重新计算合并配置。因此: 1. 在排序/筛选后重新计算spanConfig(在computed属性中,依赖于排序/筛选后的数据)。 2. 注意:排序/筛选后的数据需要重新组,然后计算合并配置。 四、复杂合并(多列同合并规则) 如果需要合并的列有同的合并规则,则需要为每一列独立计算合并配置。 五、避免的坑 1. 返回[0,0]表示显示,但注意能返回[0,1],因为[0,1]表示占0行1列,实际上显示,但有时会留下空白。 2. 合并行数计算错误可能导致表格行错位。 六、替代方案建议 如果经过上述优化仍然无法解决性能问题,那么可能需要考虑前面提到的替代方案(数据预处理合并法或CSS视觉合并法),特别是当数据量非常大时(比如上万行)。 相关问题: 1. 如何动态更新el-table的合并单元格? 2. 在el-table中,排序后合并单元格错位怎么解决? 3. 使用span-methods合并单元格时,如何提高性能? 4. 如何实现跨页合并单元格? </think># el-table 合并大量单元格的常见问题及解决方案 在使用 Element UIel-table 组件进行大量单元格合并时,`span-methods`方法可能出现各种问题。我将针对常见问题提供解决方案,并优化合并大量单元格的性能。 ## 常见问题及解决方案 ### 1. 合并错位问题 **问题原因**:合并计算逻辑未考虑数据排序或筛选后的索引变化 **解决方案**:使用唯一标识符代替行索引计算 ```javascript methods: { arraySpanMethod({ row, column, rowIndex }) { // 使用数据中的唯一标识符代替行索引 const currentId = row.project_id; // 计算合并范围 let rowspan = 1; if (column.property === 'project_name') { const rows = this.tableData; const startIndex = rows.findIndex(item => item.project_id === currentId); const endIndex = rows.findIndex(item => item.project_id !== currentId && item.project_id > currentId); rowspan = endIndex === -1 ? rows.length - startIndex : endIndex - startIndex; // 只对每个项目的第一个单元格返回合并范围 if (rowIndex !== startIndex) { return [0, 0]; } return [rowspan, 1]; } return [1, 1]; } } ``` ### 2. 性能问题(大量单元格渲染卡顿) **原因**:`span-methods`在渲染每个单元格时都会调用,导致性能瓶颈 **优化方案**:预计算合并信息 + 虚拟DOM优化 ```javascript computed: { // 预计算所有合并信息 spanMap() { const map = new Map(); let currentId = null; let startIndex = 0; this.tableData.forEach((row, index) => { if (row.project_id !== currentId) { if (currentId !== null) { // 存储合并信息:起始索引行数 map.set(currentId, { startIndex, rowSpan: index - startIndex }); } currentId = row.project_id; startIndex = index; } }); // 处理最后一组数据 if (currentId !== null) { map.set(currentId, { startIndex, rowSpan: this.tableData.length - startIndex }); } return map; } }, methods: { arraySpanMethod({ row, column, rowIndex }) { if (column.property === 'project_name') { const spanInfo = this.spanMap.get(row.project_id); // 只对合并组的第一个单元格设置rowspan if (rowIndex === spanInfo.startIndex) { return [spanInfo.rowSpan, 1]; } else { return [0, 0]; // 其余单元格显示 } } return [1, 1]; } } ``` ### 3. 排序/筛选后合并失效 **解决方案**:在排序/筛选操作后重新计算合并信息 ```javascript methods: { handleSortChange(column) { // 执行默认排序 this.sortColumn = column.prop; this.sortOrder = column.order; // 重新排序后重新计算合并信息 this.$nextTick(() => { this.$refs.table.doLayout(); this.recalculateSpans(); }); }, recalculateSpans() { // 强制刷新合并信息 this.spanMap = null; this.$nextTick(() => { this.spanMap = this.calculateSpanMap(); }); } } ``` ### 4. 跨页合并问题 **解决方案**:使用分页感知的合并逻辑 ```javascript methods: { arraySpanMethod({ row, column, rowIndex }) { if (column.property === 'project_name') { const spanInfo = this.spanMap.get(row.project_id); const isFirstInPage = this.isFirstInPage(row.project_id); // 只对当前页的第一个单元格设置rowspan if (isFirstInPage) { const remainingRows = this.getRemainingRows(row.project_id); return [remainingRows, 1]; } return [0, 0]; } return [1, 1]; }, isFirstInPage(projectId) { const pageStart = (this.currentPage - 1) * this.pageSize; const pageData = this.tableData.slice(pageStart, pageStart + this.pageSize); return pageData.findIndex(item => item.project_id === projectId) === 0; }, getRemainingRows(projectId) { let count = 0; const pageStart = (this.currentPage - 1) * this.pageSize; for (let i = pageStart; i < this.tableData.length; i++) { if (this.tableData[i].project_id === projectId) { count++; } else if (count > 0) { break; } } return Math.min(count, this.pageSize); } } ``` ## 替代方案:数据预处理合并法 对于大规模数据合并,数据预处理方法性能更优: ```javascript computed: { mergedTableData() { const mergedData = []; let currentProject = null; this.rawData.forEach(row => { if (row.project_id !== currentProject?.project_id) { // 新项目组 currentProject = { project_id: row.project_id, project_name: row.project_name, events: [row.event_name] }; mergedData.push(currentProject); } else { // 添加到现有项目组 currentProject.events.push(row.event_name); } }); return mergedData; } } ``` 表格渲染: ```html <el-table :data="mergedTableData"> <el-table-column prop="project_id" label="项目ID" /> <el-table-column prop="project_name" label="项目名称" /> <el-table-column label="事件"> <template #default="{row}"> <div v-for="(event, index) in row.events" :key="index"> {{ event }} </div> </template> </el-table-column> </el-table> ``` ## 性能优化建议 1. **虚拟滚动**:对于超大数据量(>1000行),使用虚拟滚动组件 ```html <el-table-v2 :columns="columns" :data="tableData" :row-height="50" :width="1000" :height="500" /> ``` 2. **分页处理**:合理分页减少单页渲染量(推荐单页 ≤ 100行) ```html <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[50, 100, 200]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total"> </el-pagination> ``` 3. **延迟渲染**:使用 `v-if` 控制表格渲染时机 ```html <div v-if="isDataReady"> <el-table :data="tableData"> <!-- 表格内容 --> </el-table> </div> ``` ## 相关问题 1. 如何实现跨页合并单元格时的数据一致性?[^1] 2. 在大量数据下,有哪些替代 `span-methods` 的高性能合并方案?[^2] 3. 如何处理合并单元格后的编辑功能?[^3] 4. 如何优化移动端上的表格合并渲染性能?[^1] [^1]: 单元格合并实现思路 [^2]: 数据项合并的预处理方法 [^3]: 合并行内操作功能实现
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值