当前位置: 首页 > news >正文

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

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

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) } },
http://www.gsyq.cn/news/115335.html

相关文章:

  • EmotiVoice在电子词典中的潜在用途挖掘
  • 2025全球智能机械与电子产品博览会创新科技成果发布会在澳门举办
  • 快速部署EmotiVoice:一键生成带情感的AI语音
  • 2025有生产资质的精密压延机厂家TOP5权威推荐:资深厂商 - mypinpai
  • 1.8 上下文管理秘籍:从零构建长短期记忆,让你的 Agent 不再健忘
  • 2.1 Agent 开发新范式!LangGraph 从链式思维到图状态的革命
  • 基于YOLO11改进MFM的进气插头表面缺陷检测与识别
  • 设计少儿编程逻辑训练AI助手,通过图形化编程积木操作,AI实时判断代码逻辑错误,提供引导提示,非直接给出答案,记录能力成长轨迹。
  • 【赵渝强老师】在PostgreSQL中访问Oracle
  • 【收藏必备】大模型时代AI Agent开发:智能客服实战指南与产品经理工作框架
  • 年底“年假清零”成难题?看管理者如何规避合规与成本双重风险
  • 48、Linux DBMS 管理全攻略
  • 青否AI员工源头厂商agent工作流更加智能高效,支持私有化部署!
  • 2025年知识获取功能平台推荐:考试知识库导入、浏览器知识收 - myqiye
  • Python包管理告别龟速下载:uv工具国内镜像与离线安装实战
  • 2025年12月高压反应釜推荐品牌,选什么品牌能够助力企业选购适配需求的实验设备,附上选购建议 - 品牌推荐大师1
  • 展厅设计哪家靠谱?纪念馆展馆设计哪家好? - mypinpai
  • 太贵?爱创猫靠谱省钱
  • 基于SpringBoot的宠物医院管理系统(毕业设计项目源码+文档)
  • 抗衰老必选!NMN十大品牌评测,奥本元名列第一 - 资讯焦点
  • 面向临床的TCR闭环:在手术室/ICU协同场景与多中心科研中的实证研究(上)
  • 基于SpringBoot的足球队管理系统毕业设计项目源码
  • 面向临床的TCR闭环:在手术室/ICU协同场景与多中心科研中的实证研究(下)
  • 【赵渝强老师】PostgreSQL的物理存储结构
  • 合规即代码的延伸:国产 DevOps 平台如何利用平台扩展能力,自动验证信创基础设施的配置合规性
  • BJ-字符串
  • 从“连接器”到“封装载体”:高多层板的进化
  • python编程实战(三)
  • 【光子 AI】《Jeff Dean 传记:Google 工程师的传奇人生》
  • 校园快递代取|基于springboot + vue校园快递代取系统(源码+数据库+文档)​