el-table实现虚拟滚动

Element UI el-table万级数据渲染优化:虚拟滚动实战方案 在前端开发中,大数据量渲染是常见的性能挑战。当数据量达到数千甚至上万条时,传统的全量DOM渲染模式会导致严重的性能问题,表现为页面卡顿、滚动不流畅甚至浏览器崩溃。其核心原理在于浏览器对大量DOM节点的操作和样式计算消耗巨大资源。为解决这一问题,按需渲染成为关键技术思路,其中虚拟滚动(Virtual Scrolling)通过动态计算可视区域、只渲染可见数据行,并利用占位元素模拟完整滚动条,实现了DOM节点数量的恒定,从而大幅提升性能。这种技术方案在数据中台、后台管理系统等需要展示海量数据的场景中具有重要价值。 阅读详情
AI摘要

文章介绍了如何使用基于Element-UI的el-table-virtual-scroll组件来处理大量数据的表格,通过虚拟滚动技术减少滚动时的卡顿问题,提供代码示例和API说明。

el-table-virtual-scroll

基于Element-UI的Table 组件开发的虚拟滚动组件,支持动态高度,解决数据量大时滚动卡顿的问题。

依赖:Vue2和ElementUI。

预览:https://xiaocheng555.github.i...

github:https://github.com/xiaocheng5...

el-table-virtual-scroll.vue 组件代码如下:

<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>

用法

<VirtualScroll
  :data="list"
  :height="62"
  key-prop="id"
  @change="(renderData) => virtualList = renderData">
  <el-table 
    row-key="id" 
    :data="virtualList" 
    height="500px">
  </el-table>
</VirtualScroll>

...

import VirtualScroll from './el-table-virtual-scroll'

export default {
  component: {
    VirtualScroll
  },
  data () {
    list: [
      {
        id: 1,
        text: 'content'
      },
      // ...... 省略n条
      {
        id: 2000,
        text: 'content2'
      }
    ],
    virtualList: []
  }
}

API

Props

参数说明类型可选值默认值
data总数据Array必填
height每一行的预估高度number—60
buffer顶部和底部缓冲区域,值越大显示表格的行数越多Number—500
keyPropkey值,data数据中的唯一idstring—id
throttleTime滚动事件的节流时间number—100

Methods

方法名说明参数
scrollTo滚动到第几行index
update更新-
reset重置-

Events

事件名称说明回调参数
change计算完成真实显示的表格行数(renderData, start, end):renderData 真实渲染的数据,start和end指的是渲染的数据在总数据的开始到结束的区间范围
Vue项目el-table卡到爆?试试这个虚拟滚动方案,性能提升肉眼可见 本文针对Vue项目中el-table在大数据量下卡顿问题,提出虚拟滚动优化方案。通过umy-ui的u-table组件实现虚拟滚动,显著减少DOM节点数量,提升渲染性能和用户体验。文章详细介绍了虚拟滚动原理、umy-ui集成方法及性能优化配置,帮助开发者解决el-table性能瓶颈。 阅读详情

相关推荐

Vue2 - vue-virtual-scroller 长列表优化原理

Vue2 - vue-virtual-scroller 长列表优化原理。虚拟滚动

qq_40147756的博客 2854

使用虚拟滚动优化el-table长列表加快运行速度

项目背景: 在vue2中el-table的数据量太大,并且有点击单元格选中和鼠标框选单元格选中数据,并对数据进行操作的功能,所以在不使用虚拟滚动前,非常卡顿,使用后完美解决卡顿问题.

前端程序媛_Ying博客 5287

从el-table到u-table/ux-grid:实战虚拟滚动与动态高度适配,打造高性能Vue表格

本文详细介绍了从el-table迁移到u-table/ux-grid的实战经验,重点解析了虚拟滚动技术的优势与实现方法。通过对比测试,u-table在渲染1万条数据时仅需200毫秒,性能远超el-table。文章还提供了动态高度适配、样式定制及性能优化等实用技巧,帮助开发者打造高性能Vue表格应用。

weixin_30664051的博客 508

文件异步上传使用虚拟滚动el-table-virtual-scroll加载数据

最近在写一个批量导入数据的功能,需要通过上传文件异步导入调接口,将后台返回Excel文件里的数据不做分页用列表展示出来,再加上需要在列表嵌入输入框,所以加载大量数据渲染的时候要加载很久,需要用到虚拟滚动加载。这个插件用于虚拟滚动加载数据,仅支持vue2,具体使用参考下面地址,案例里也有源码示例,挺好用的,非常推荐!展示在列表,嵌入输入框可修改别名,后台返回的数据一次最少大约有2000条左右而且不做分页,需要使用虚拟滚动加载。进行删除覆盖可以保证获取到新上传的文件,每次点击导入就会通过。

学习记录 2362

告别分页器!用ElementUI的el-table-infinite-scroll插件实现滚动到底部自动加载数据

本文详细介绍了如何使用ElementUI的el-table-infinite-scroll插件实现表格滚动到底部自动加载数据的功能,替代传统分页器。通过核心原理分析、环境准备、基础实现到高级配置与性能优化,为开发者提供了一套完整的解决方案,特别适合需要流畅浏览体验的数据密集型应用。

weixin_30493401的博客 592

vue3-seamless-scroll实现el-table的无线滚动出了问题,如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 1191

elementUI中的 el-table 实现虚拟滚动

解决该问题主要是用虚拟滚动的思路。引发页面卡顿的原因主要是由于数据量太大导致渲染的 dom 较多,然后页面就卡顿了。使用了 elementUI 中的 el-table 组件,不使用分页,当表格数据过多时导致页面卡顿;下面使用 element 中的 el-table 实现一下虚拟滚动来解决这个问题。

Hyanl的博客 9754

virtual-scroll:用于创建自定义滚动行为的低级库

虚拟滚动 一个2kb压缩的低级库,可创建具有触摸和键盘支持的自定义滚动条。 这在很大程度上受Bartek Drozdz VirtualScroll实用程序的启发。 请参阅他的以供参考。 特征 可以创建具有不同元素的多个实例作为目标 让您进行实际的滚动逻辑:使用CSS变换,WebGL动画或任何您喜欢的东西 本机箭头键支持和Shift /空格键支持模仿默认浏览器行为 对于基于虚拟滚动的高级库,请检查或 。 安装 npm i virtual-scroll -S 用法和API 建设者 new VirtualScroll(options) el :移动触摸事件的目标元素。 默认为窗口。 mouseMultiplier :所有鼠标滚轮(包括Firefox)的通用倍增器。 默认为1。 touchMultiplier :此修饰符使触摸动作可变,使滚动比手指移动快。 默认为2。 firefoxMul

vue3 + elementplus 手动实现 el-table 虚拟滚动

vue3 + elementplus 手动实现 el-table 虚拟滚动

weixin_61769998的博客 738

C#与Vector XL驱动库实战:CAN通道配置与端口访问详解

本文详细解析了使用C#调用Vector XL驱动库进行CAN总线通信开发的核心步骤。重点阐述了如何通过XL_GetDriverConfig获取硬件通道信息,并厘清channelMask与accessMask的区别与转换关系,最终指导开发者正确使用XL_OpenPort函数配置并打开CAN端口,为构建稳定的汽车电子测试与诊断应用奠定基础。

weixin_28452161的博客 362

Godot 4.x 实现 JRPG 回合制战斗系统:架构、状态机与实战优化

游戏开发中,状态机是管理复杂逻辑流转的核心设计模式,尤其在回合制战斗这类事件驱动的场景中。其原理是通过定义有限的状态和明确的转移条件,来控制系统在不同阶段的行为,从而实现清晰、可维护的流程控制。这项技术的价值在于能够将杂乱的条件判断代码结构化,降低模块间的耦合度,提升代码的可读性和可扩展性。在游戏开发领域,状态机广泛应用于角色AI、UI流程、战斗系统等场景。本文以Godot引擎为例,深入探讨如何运用节点与信号驱动架构,构建一个健壮的JRPG(日式角色扮演游戏)回合制战斗系统。内容涵盖从核心的**状态机**设

weixin_33749242的博客 500

el-table实现虚拟滚动 | 一篇讲清什么是虚拟滚动,该如何实现 | Vue2 | ElementUI

一篇搞定虚拟滚动,小白也能看懂的文章

x1145540679的博客 9990

每天一个优秀提示词学习收藏 - 文本去AI化(四)

宝子们,今天不藏私啦!我把这段时间四处搜罗、潜心钻研出来的文本去AI化Prompt 提示词大礼包双手奉上,这可都是能让你的 AI 创作水平原地起飞的干货!走过路过不要错过,赶紧码住,开启你的 AI 创作进阶之旅吧!

2446

vue.js - el-table-virtual-scroll实现虚拟滚动

基于Element-UI的Table 组件开发的虚拟滚动组件,支持动态高度,解决数据量大时滚动卡顿的问题。依赖:Vue2和ElementUI。

細水、長流√的专栏 5146

欢乐熊大话蓝牙知识16:蓝牙是怎么找设备的?扫描与广播的“对话内幕”

蓝牙是怎么找设备的?扫描与广播的对话技术介绍

hoony123的博客 1382

Adams与matlab联合仿真的一些小技巧

Adams与simulink联合仿真之快速设置初值 去年到现在一直做的两个项目要用到Adams与simulnk联合仿真,虽然网上有很多这方面的教程,但都比较基本,要实现一些稍微复杂的要求就比较困难了,比如我需要改变模型的初始位姿,原来的方式是在adams中设置,再生成联合仿真需要的文件,再在matlab中进行调用和仿真,如果工况多的话这样就特别耗时耗力,进过长时间的摸索,终于找出了在matlab中直接改变Adams模型参数的方法,下面具体说明一下。 我这里的模型是一个小球通过弹簧连接在坐标原点,仿真开始后

weixin_40962901的博客 4785

element表格el-table组件实现虚拟滚动,解决数据量大渲染DOM过多而卡顿问题

element表格el-table组件实现虚拟滚动,解决数据量大渲染DOM过多而卡顿问题

D浩DzD的博客 1万+

RK3588上从零部署Facenet人脸识别:PyTorch转ONNX再到RKNN的完整避坑指南

本文提供了在RK3588开发板上从零部署Facenet人脸识别模型的完整指南。详细介绍了从PyTorch模型导出、转换为ONNX格式,再通过RKNN-Toolkit2转换为RKNN格式的完整流程,并重点分享了环境配置、算子兼容性处理、量化调优及板端部署中的关键步骤与避坑经验。

river的博客 464

【虚拟滚动】vue2 element el-table组件虚拟滚动效果

首先,虚拟滚动的场景是什么? 项目中可能会遇到一些通用情况,它要求列表不能分页处理,也不能懒加载,必须一次性展示“所有数据”,且不能有过分的卡顿等问题。这次就以第二种情况来说明如何处理,接上一篇博客 一文搞懂web端国际化方案(以vue2+elementUI为例,包含远程获取国际化)为了给多语言提供一个可供展示和修改的页面,前端自己实现了一个虚拟滚动且能修改多语言的页面。 直接上代码:

Li_Ning21的博客 2813

Tmux学习总结

Tmux 重要概念 使用 Tmux 的时候千万不要去背指令,所有的指令都可以在 .tmux.conf 配置文件中绑定自己顺手的快捷键,也可以配置开启鼠标。 这个是我的配置文件:https://github.com/zuorn/tmux.conf 在Tmux逻辑中,需要分清楚Server > Session > Window > Pane这个大小和层级顺序是极其重要的,直接关系到工作效率: Server:是整个tmux的后台服务。有时候更改配置不生效,就要使用tmux kill-

满目星辰 579

【Android调试】高通adb识别不到设备的完整排查指南:从驱动到端口一步到位

本文系统梳理高通(Qualcomm)平台Android设备adb无法识别的完整排查流程。从最基础的USB连接检查开始,到Windows设备管理器中驱动状态的判断、高通USB驱动的正确安装与更新方法,再到adb端口被占用、USB调试未开启、驱动签名校验失败等高频场景的解决方案。每一步均配截图和操作命令,文末附常见报错速查表,适合做系统开发、刷机调试或者Android Framework bringup时遇到adb不通的工程师快速定位。

weixin_44081096的博客 282

vue+element-ui el-table组件二次封装实现虚拟滚动,解决数据量大渲染DOM过多而卡顿问题

vue+element-ui el-table组件二次封装实现虚拟滚动,解决数据量大渲染DOM过多而卡顿问题

wocwin的博客 5728

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

大量数据el-tabel的虚拟滚动

虚拟滚动是一种优化技术,可以在大量数据的情况下,只渲染可视区域的内容,而不是整个数据集。在这个示例中,我们通过动态计算每一行的高度,然后根据可视区域的高度来确定可视区域的数据范围。这样即使行高不固定,也能实现虚拟滚动的效果。组件本身不支持虚拟滚动,但你可以通过一些额外的工作来实现虚拟滚动的效果。的高度,并在其内部使用滚动容器,监听滚动事件,动态地渲染可视区域的数据。元素的子元素表示的。在实际应用中,你可能需要根据实际情况对代码进行调整。这里提供一个简单的示例代码,演示如何通过监听滚动事件来实现虚拟滚动。

qq_40658616的博客 1982

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

告别卡顿!手写一个el-table虚拟滚动懒加载指令(支持搜索定位与高亮)

本文详细介绍了如何为el-table实现虚拟滚动懒加载指令,有效解决大数据量渲染导致的卡顿问题。通过核心原理剖析、指令架构设计及增强功能实现(如搜索定位与高亮),帮助开发者提升Element-ui表格性能,适用于海量数据展示场景。

weixin_30258901的博客 301

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

el-table内嵌echarts图表时一次性渲染的导致页面加载过慢的性能问题

可以使用vxe的table图表代替element的table表格,vxe的表格可实现虚拟滚动,就是表格的虚拟加载,在表格加载时只渲染一部分的dom节点,而且vxe的表格有预加载机制,所以在滚动时加载不会照成卡顿问题。

m0_59679001的博客 437

使用el-table渲染将近200列数据渲染慢的问题

el-table表格渲染慢,使用vxe-table

qq_43791427的博客 964
上一篇: Java8 Stream 之groupingBy 分组
tyjlearning
博客等级 码龄11年 24粉丝 83原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值