vue2 element ui el-table大数据处理无分页解决方案-分片加载
实现:
当数据量大,无分页后台一次全部返回数据,如果直接el-table渲染会造成页面渲染卡死
分片加载 截取数组中指定条数返显 使用: slice
完整vue 代码,有注解,如果使用接口分页把延迟 改为 实际接口
<template> <div class="table-demo"> <!-- @scroll="testcroll" 未生效 考虑其他方式 --> <!-- 优先使用 el-table 内置 @scroll 事件(更简洁,无需手动操作DOM) --> <el-table ref="myTable" :data="tableData" height="300" border stripe > <el-table-column prop="id" label="序号" width="100" /> <el-table-column prop="name" label="姓名" width="150" /> <el-table-column prop="address" label="地址" min-width="200" /> </el-table> </div> </template> <script> // 引入 lodash 节流(若项目未集成,可使用自定义节流函数) import _ from "lodash"; export default { name: "ElTableScrollCorrect", data() { return { scrollContainer: null, originData: [], // 大数据量存储 tableData: [], // 当前页面表格渲染 pageSize: 100, // 每次加载100条(可根据性能调整,建议50-200) currentPage: 1, // 当前加载到第几页 loading: false, // 是否正在加载 noMore: false, // 是否已加载全部数据 }; }, created() { // 模拟5万条数据(原1000条可改为50000,测试大数据场景) this.generateTestData(50000); }, beforeDestroy() { // 组件销毁前,移除事件监听(防止内存泄漏) if (this.scrollContainer) { this.scrollContainer.removeEventListener( "scroll", this.handleTableScroll ); } }, mounted() { // 组件挂载后,获取内部滚动容器 this.scrollContainer = this.$refs.myTable.$el.querySelector( ".el-table__body-wrapper" ); // 绑定原生 scroll 事件 if (this.scrollContainer) { this.scrollContainer.addEventListener("scroll", this.handleTableScroll); } }, methods: { /** * 生成模拟数据(优化:批量生成,减少冗余逻辑) * @param {Number} count - 数据总量 */ generateTestData(count) { // 批量生成数据,避免手动循环的冗余写法 const data = Array.from({ length: count }, (_, index) => ({ id: index + 1, name: `用户${index + 1}`, address: `北京市朝阳区${index + 1}号街道`, })); // 冻结原始数据,禁用响应式(核心优化:减少Vue监听开销) this.originData = Object.freeze(data); // 初始化加载第一页数据 this.loadMoreData(); }, /** * 表格滚动事件处理(优化:节流处理,减少事件触发频率) * @param {Object} scrollInfo - 滚动信息对象(scrollTop/scrollHeight/clientHeight) */ handleTableScroll: _.throttle(function (scrollInfo) { const { scrollTop, scrollHeight, clientHeight } = scrollInfo.target; console.log(scrollTop, scrollHeight, clientHeight) // 滚动距离底部50px时触发加载(优化:增加边界判断,避免无效触发) const isNearBottom = scrollTop + clientHeight >= scrollHeight - 500; // 仅当接近底部、未加载中、还有数据时,才触发加载 if (isNearBottom && !this.loading && !this.noMore) { console.log('scrollInfo',scrollInfo) this.loadMoreData(); } }, 500), // 500ms内仅触发一次,优化性能 /** * 加载更多数据的核心方法(优化:逻辑严谨性,减少冗余操作) */ async loadMoreData() { // 避免重复加载(前置判断,快速返回) if (this.loading || this.noMore) return; this.loading = true; try { // 模拟接口请求延迟(实际项目替换为真实接口调用,建议用async/await) await this.mockApiRequest(); // 计算数据索引(优化:边界处理,避免超出数组长度) const start = (this.currentPage - 1) * this.pageSize; const end = Math.min(start + this.pageSize, this.originData.length); // 切片获取当前页数据并冻结(减少响应式开销) const newData = Object.freeze(this.originData.slice(start, end)); // 批量追加数据(优化:避免循环push,减少视图更新次数) this.tableData = [...this.tableData, ...newData]; // 更新分页状态 this.currentPage += 1; // 判断是否加载完毕(优化:精准判断,避免无效加载) this.noMore = end >= this.originData.length; } catch (error) { console.error("数据加载失败:", error); this.$message?.error("数据加载失败,请稍后重试"); // 新增:错误提示 } finally { // 无论成功失败,都解除加载锁(优化:避免加载状态卡死) this.loading = false; } }, /** * 模拟接口请求(优化:抽离为独立方法,便于替换真实接口) * @returns {Promise} - 模拟请求Promise */ mockApiRequest() { return new Promise((resolve) => { setTimeout(resolve, 300); // 缩短延迟时间,提升用户体验 }); }, }, }; </script> <style scoped> </style>
浙公网安备 33010602011771号