news 2026/8/7 23:54:23

当表格数据量过大的时候,如何使用不分页进行展示

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
当表格数据量过大的时候,如何使用不分页进行展示

表格数据过大的时候,渲染时间则增大。使用分页就可以解决,但是有的时候用户不想使用分页,那么前端可以监听滚动条进行懒加载,但是当数据都加载出来。数据量就又大了。

1. 组件文件名: elTableVirtualScroll.vue 通过仅渲染可视区域内的内容来减少 DOM 节点数量,从而提升页面响应速度和内存使用效率

<template> <div> <slot></slot> </div> </template> <script> import throttle from 'lodash/throttle' export default { name: 'el-table-virtual-scroll', props: { data: { type: Array, required: true }, height: { type: Number, default: 60 }, buffer: { type: Number, default: 500 }, keyProp: { type: String, default: 'id' }, throttleTime: { type: Number, default: 100 } }, data () { return { sizes: {} // 尺寸映射(依赖响应式) } }, computed: { // 计算出每个item(的key值)到滚动容器顶部的距离 offsetMap ({ keyProp, height, sizes, data }) { const res = {} let total = 0 for (let i = 0; i < data.length; i++) { const key = data[i][keyProp] res[key] = total const curSize = sizes[key] const size = typeof curSize === 'number' ? curSize : height total += size } return res } }, methods: { // 初始化数据 initData () { // 可视范围内显示数据 this.renderData = [] // 页面可视范围顶端、底部 this.top = undefined this.bottom = undefined // 截取页面可视范围内显示数据的开始和结尾索引 this.start = 0 this.end = undefined this.scroller = this.$el.querySelector('.el-table__body-wrapper') // 初次执行 setTimeout(() => { this.handleScroll() }, 100) // 监听事件 this.onScroll = throttle(this.handleScroll, this.throttleTime) this.scroller.addEventListener('scroll', this.handleScroll) window.addEventListener('resize', this.onScroll) }, // 更新尺寸(高度) updateSizes () { const rows = this.$el.querySelectorAll('.el-table__body > tbody > .el-table__row') Array.from(rows).forEach((row, index) => { const item = this.renderData[index] if (!item) return const key = item[this.keyProp] const offsetHeight = row.offsetHeight if (this.sizes[key] !== offsetHeight) { this.$set(this.sizes, key, offsetHeight) } }) }, // 处理滚动事件 handleScroll (shouldUpdate = true) { // 更新当前尺寸(高度) this.updateSizes() // 计算renderData this.calcRenderData() // 计算位置 this.calcPosition() shouldUpdate && this.updatePosition() // 触发事件 this.$emit('change', this.renderData, this.start, this.end) }, // 获取某条数据offsetTop getOffsetTop (index) { const item = this.data[index] if (item) { return this.offsetMap[item[this.keyProp]] || 0 } return 0 }, // 获取某条数据的尺寸 getSize (index) { const item = this.data[index] if (item) { const key = item[this.keyProp] return this.sizes[key] || this.height } return this.height }, // 计算只在视图上渲染的数据 calcRenderData () { const { scroller, data, buffer } = this // 计算可视范围顶部、底部 const top = scroller.scrollTop - buffer const bottom = scroller.scrollTop + scroller.offsetHeight + buffer // 二分法计算可视范围内的开始的第一个内容 let l = 0 let r = data.length - 1 let mid = 0 while (l <= r) { mid = Math.floor((l + r) / 2) const midVal = this.getOffsetTop(mid) if (midVal < top) { const midNextVal = this.getOffsetTop(mid + 1) if (midNextVal > top) break l = mid + 1 } else { r = mid - 1 } } // 计算渲染内容的开始、结束索引 let start = mid let end = data.length - 1 for (let i = start + 1; i < data.length; i++) { const offsetTop = this.getOffsetTop(i) if (offsetTop >= bottom) { end = i break } } // 开始索引始终保持偶数,如果为奇数,则加1使其保持偶数【确保表格行的偶数数一致,不会导致斑马纹乱序显示】 if (start % 2) { start = start - 1 } // console.log(start, end, 'start end') this.top = top this.bottom = bottom this.start = start this.end = end this.renderData = data.slice(start, end + 1) }, // 计算位置 calcPosition () { const last = this.data.length - 1 // 计算内容总高度 const wrapHeight = this.getOffsetTop(last) + this.getSize(last) // 计算当前滚动位置需要撑起的高度 const offsetTop = this.getOffsetTop(this.start) // 设置dom位置 const classNames = ['.el-table__body-wrapper', '.el-table__fixed-right .el-table__fixed-body-wrapper', '.el-table__fixed .el-table__fixed-body-wrapper'] classNames.forEach(className => { const el = this.$el.querySelector(className) if (!el) return // 创建wrapEl、innerEl if (!el.wrapEl) { const wrapEl = document.createElement('div') const innerEl = document.createElement('div') wrapEl.appendChild(innerEl) innerEl.appendChild(el.children[0]) el.insertBefore(wrapEl, el.firstChild) el.wrapEl = wrapEl el.innerEl = innerEl } if (el.wrapEl) { // 设置高度 el.wrapEl.style.height = wrapHeight + 'px' // 设置transform撑起高度 el.innerEl.style.transform = `translateY(${offsetTop}px)` // 设置paddingTop撑起高度 // el.innerEl.style.paddingTop = `${offsetTop}px` } }) }, // 空闲时更新位置 updatePosition () { this.timer && clearTimeout(this.timer) this.timer = setTimeout(() => { this.timer && clearTimeout(this.timer) // 传入false,避免一直循环调用 this.handleScroll(false) }, this.throttleTime + 10) }, // 【外部调用】更新 update () { console.log('update') this.handleScroll() }, // 【外部调用】滚动到第几行 scrollTo (index, stop = false) { const item = this.data[index] if (item && this.scroller) { this.updateSizes() this.calcRenderData() this.$nextTick(() => { const offsetTop = this.getOffsetTop(index) this.scroller.scrollTop = offsetTop // 调用两次scrollTo,第一次滚动时,如果表格行初次渲染高度发生变化时,会导致滚动位置有偏差,此时需要第二次执行滚动,确保滚动位置无误 if (!stop) { setTimeout(() => { this.scrollTo(index, true) }, 50) } }) } }, // 【外部调用】重置 reset () { this.sizes = {} this.scrollTo(0, false) } }, watch: { data () { this.update() } }, created () { this.$nextTick(() => { this.initData() }) }, beforeDestroy () { if (this.scroller) { this.scroller.removeEventListener('scroll', this.onScroll) window.removeEventListener('resize', this.onScroll) } } } </script> <style lang='less' scoped> </style>

2. 使用案例:在文件中引入组件,tableData1变量是表格全部数据,tableData则是展示的数据,tableDataChange用来监听容器滚动条,进而计算展示数据

<VirtualScroll :data="tableData1" :height="62" key-prop="id" @change="tableDataChange"> <el-table :data="tableData" border ref="tables" height="50vh" v-loading="tableLoading" style="width: 100%;"> </el-table> </VirtualScroll>
tableDataChange(renderData) { this.tableData = renderData if(this.tableData.length > 0) { this.tableData.unshift(this.formObject) } },
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 20:48:34

工业互联网产业联盟:高标准数字园区建设研究报告 2025

本报告由工业互联网产业联盟联合华为等企业编写&#xff0c;围绕高标准数字园区建设展开全面研究&#xff0c;旨在为园区数字化深化转型提供技术指引与案例参考。一、研究背景与核心内涵背景&#xff1a;在新一轮科技革命与产业变革推动下&#xff0c;传统园区面临资源浪费、产…

作者头像 李华
网站建设 2026/8/7 20:03:13

共商AI时代发展新路径 第十六届亚洲电子论坛举办

12月4日&#xff0c;海风温润&#xff0c;思想激荡&#xff0c;一场亚洲电子信息产业的年度思想盛宴与创新庆典在澳门拉开帷幕。当天下午&#xff0c;第十六届亚洲电子论坛&#xff08;AEF&#xff09;暨全球智能科技峰会在澳门举办。来自全球多个国家与地区的产业代表、专家学…

作者头像 李华
网站建设 2026/8/7 13:43:12

软考—系统集成项目管理工程师计算公式汇总

系统集成项目管理工程师虽然技术题目不算多&#xff0c;但考试中也会涉及到一些计算题。一、计算公式 基础&#xff1a; 1.计划值&#xff08;PV&#xff09;&#xff1a;PV 计划工作量 计划单价&#xff0c;与检查时间点有关。 2.挣值&#xff08;EV&#xff09;&#xff1a…

作者头像 李华
网站建设 2026/8/7 22:09:36

AI元人文构想:在黑箱与元白箱之间的抉择分析

AI元人文构想&#xff1a;在黑箱与元白箱之间的抉择分析一、关于本文论述策略与理论立场的说明本文采用 “LLM黑箱”与“AI元人文元白箱” 的二元对立框架进行论述&#xff0c;旨在通过极致的对比张力&#xff0c;揭示当前技术路径潜藏的文明风险与另一条根本性道路的存在。我们…

作者头像 李华
网站建设 2026/8/7 22:10:01

AI元人文构想:意义行为原生论——回应质疑

AI元人文构想&#xff1a;意义行为原生论——回应质疑面对关于“AI元人文构想”的诸多深刻质疑&#xff0c;我认为首要之事&#xff0c;是澄清一个根本性的范式跃迁。许多担忧&#xff0c;源自于不自觉地用旧时代的“硅基工具范式”眼镜&#xff0c;来审视一个试图超越该范式的…

作者头像 李华
网站建设 2026/8/7 22:09:40

15、网络相似度与二分网络的构建与分析

网络相似度与二分网络的构建与分析 一、构建相似度网络的前期准备 在构建基于相似度的网络时,若列表 protein 包含每个食品项中的蛋白质含量,可对其进行二分处理。以下是两种实现方式: 1. 普通 Python 方式 import statistics threshold = statistics.mean(protein) …

作者头像 李华