news 2026/5/16 17:27:09

列表大量dom渲染导致浏览器卡顿的解决方案:虚拟滚动(vue)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
列表大量dom渲染导致浏览器卡顿的解决方案:虚拟滚动(vue)

大量dom导致浏览器渲染了全部dom导致页面严重卡顿、交互延迟、CPU 占用飙升、内存急剧增大,滚动频繁掉帧等问题,细想一下:用户并不会同时看到所有数据,所以我们只需借助虚拟滚动,只渲染用户可视区域内的数据,减少大量 DOM 和渲染压力,提升页面流畅度及用户体感。

一、具体实现

  1. 外层容器:固定高度 +overflow-y: auto,这是用户视图
  2. 占位 div:高度设为总条数 × 行高,它不显示任何内容,只负责撑出滚动条
  3. 真实渲染区position: absolute+transform: translateY(),根据滚动位置动态移动

用户滚动时,监听scrollTop,算出当前视图下应该展示哪几条数据,然后:

  • 更新真实渲染区的数据
  • 更新translateY,模拟跟着滚动条走

这样用户感觉自己在滚一个长列表,实际上 DOM 节点始终只有十几个。

如图:

二、核心实现

// 1. 起始索引:根据滚动距离算出第一个可见项 startIndex = Math.floor(scrollTop / itemHeight) // 2. 结束索引:起始 + 可视区能容纳的行数 endIndex = startIndex + Math.ceil(containerHeight / itemHeight) // 3. 偏移量:真实渲染区相对于顶部的位置 offset = startIndex * itemHeight

例如:scrollTop = 500itemHeight = 50containerHeight = 500

startIndex = 500 / 50 = 10(从第 10 条开始渲染)

endIndex = 10 + 10 = 20(渲染到第 20 条)

offset = 10 × 50 = 500(真实渲染区向下移动 500px)

三、完整代码

vue3+TS

<template> <div ref="containerRef" class="virtual-list" :style="{ height: `${containerHeight}px` }" @scroll="handleScroll" > <!-- 占位:撑出滚动条 --> <div class="virtual-list__phantom" :style="{ height: `${totalHeight}px` }" /> <!-- 真实渲染区:transform 定位 --> <div class="virtual-list__content" :style="{ transform: `translateY(${offset}px)` }" > <div v-for="item in visibleData" :key="item.id" class="virtual-list__item" :style="{ height: `${itemHeight}px` }" > <slot :item="item">{{ item.name }}</slot> </div> </div> </div> </template> <script setup lang="ts"> import { ref, computed } from 'vue'; interface Item { id: number | string; [key: string]: any; } const props = withDefaults( defineProps<{ data: Item[]; itemHeight?: number; containerHeight?: number; buffer?: number; }>(), { itemHeight: 50, containerHeight: 500, buffer: 5, } ); const containerRef = ref<HTMLElement | null>(null); const scrollTop = ref(0); // 总高度 const totalHeight = computed(() => props.data.length * props.itemHeight); // 可视区能容纳的行数 const visibleCount = computed(() => Math.ceil(props.containerHeight / props.itemHeight) ); // 起始索引(减 buffer 避免向上滚动时白屏) const startIndex = computed(() => Math.max(0, Math.floor(scrollTop.value / props.itemHeight) - props.buffer) ); // 结束索引(加 2 倍 buffer 让上下都有缓冲) const endIndex = computed(() => Math.min( props.data.length, startIndex.value + visibleCount.value + props.buffer * 2 ) ); // 需要渲染的数据切片 const visibleData = computed(() => props.data.slice(startIndex.value, endIndex.value) ); // 偏移量(!关键,渲染区模拟在正确位置) const offset = computed(() => startIndex.value * props.itemHeight); function handleScroll(e: Event) { scrollTop.value = (e.target as HTMLElement).scrollTop; } </script> <style scoped> .virtual-list { position: relative; overflow-y: auto; border: 1px solid #ddd; } .virtual-list__phantom { position: absolute; top: 0; left: 0; right: 0; z-index: -1; } .virtual-list__content { position: absolute; top: 0; left: 0; right: 0; will-change: transform; } .virtual-list__item { display: flex; align-items: center; padding: 0 16px; border-bottom: 1px solid #eee; box-sizing: border-box; } </style>

使用方式:

<VirtualList :data="list" :item-height="50" :container-height="500"> <template #default="{ item }"> <span>#{{ item.id }}</span> <span style="margin-left: 20px">{{ item.name }}</span> </template> </VirtualList>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/14 16:32:34

WaveTools:终极鸣潮游戏优化工具箱,一键解锁120帧流畅体验

WaveTools&#xff1a;终极鸣潮游戏优化工具箱&#xff0c;一键解锁120帧流畅体验 【免费下载链接】WaveTools &#x1f9f0;鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools 你是否在为《鸣潮》游戏的60帧锁帧限制而烦恼&#xff1f;是否希望在高性…

作者头像 李华
网站建设 2026/4/14 16:28:33

Flowise图文实战手册:可视化节点连线构建Zapier自动化工作流

Flowise图文实战手册&#xff1a;可视化节点连线构建Zapier自动化工作流 你是不是也遇到过这样的场景&#xff1a;想用AI模型做个智能客服&#xff0c;或者把公司文档变成问答机器人&#xff0c;但一看到要写代码、调API、处理各种复杂的逻辑链&#xff0c;头就大了&#xff1…

作者头像 李华
网站建设 2026/4/14 16:27:51

手把手教你用Arduino+ESP8266+Blinker实现智能家居远程控制(附完整代码)

从零构建智能家居控制中枢&#xff1a;ArduinoESP8266Blinker实战指南 智能家居早已不再是科幻电影中的场景&#xff0c;而是逐渐走进寻常百姓家的实用技术。想象一下&#xff0c;炎炎夏日下班路上提前打开家中空调&#xff0c;或是深夜躺在床上发现客厅灯没关时用手机一键关闭…

作者头像 李华
网站建设 2026/4/14 16:27:34

三分钟搭建本地AI OpenClaw部署实操教程 | 无需命令行

前言 在本地AI智能体快速普及的当下&#xff0c;OpenClaw&#xff08;小龙虾&#xff09;凭借「纯本地运行、零代码部署、全场景自动化」的核心优势&#xff0c;成为2026年办公人群、技术爱好者优选的AI工具。相比旧版本&#xff0c;全新v2.6.2进一步优化了部署流程、兼容性与…

作者头像 李华
网站建设 2026/5/13 15:57:20

人工智能之数学基础:求解约束非线性规划问题之外点法

本文重点 求解约束非线性规划问题有多种方法,本文我们将学习外点法,外点法可以将求解约束非线性规划问题转化为求解一系列无约束极小化问题的一类制约函数法。 外点法的介绍(外部惩罚函数法) 这个就是约束的非线性规划问题,那么我们如何才可以使用外点法来求解呢? 首先…

作者头像 李华