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

虚拟滚动列表如何实现?


highlight: a11y-dark

虚拟滚动列表,虚拟滚动的关键在于只渲染当前视口内可见的数据项,而不是一次性渲染所有数据项。这可以显著提高性能,尤其是在处理大量数据时。

以下是一个完整的虚拟滚动列表的示例代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Virtual Scrolling</title><style>#container {width: 500px;height: 700px;margin: 30px;overflow: auto;position: relative;border: 1px solid #ccc;}.item {position: absolute;width: 100%;background-color: #bfc;border-radius: 10px;margin: 2px 0;padding: 10px;box-sizing: border-box;}</style></head><body><div id="container"></div><script>const container = document.getElementById("container");const itemHeight = 50;const containerHeight = 700;const buffer = 5;let data = [];let visibleData = [];let startIndex = 0;function loopFun(num) {data = Array.from({ length: num }, (_, index) => index);handleScroll();}function handleScroll() {const scrollTop = container.scrollTop;const visibleStart = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);const visibleEnd = Math.min(data.length,visibleStart + Math.ceil(containerHeight / itemHeight) + buffer * 2);startIndex = visibleStart;visibleData = data.slice(visibleStart, visibleEnd);renderVisibleData();}function renderVisibleData() {container.innerHTML = "";visibleData.forEach((item, index) => {const div = document.createElement("div");div.className = "item";div.style.top = (startIndex + index) * itemHeight + "px";div.textContent = `数据-${item}`;container.appendChild(div);});}function throttle(func, limit) {let inThrottle;return function () {const args = arguments;const context = this;if (!inThrottle) {func.apply(context, args);inThrottle = true;setTimeout(() => (inThrottle = false), limit);}};}loopFun(1000);const throttledHandleScroll = throttle(handleScroll, 100);container.addEventListener("scroll", throttledHandleScroll);window.addEventListener("beforeunload", () => {container.removeEventListener("scroll", throttledHandleScroll);});</script></body>
</html>

上面一大串代码,看起来比较难看,在下边我会拆开了一点点来说明。先来看一下在页面上的展示效果,如下:

在这里插入图片描述

在这里插入图片描述

对比两张效果图可以看到,不论怎么滚动,页面实际上展示的永远是 23 条数据。

声明的变量:

const container = document.getElementById("container"); // 获取元素
const itemHeight = 50; // 每个数据项的高度
const containerHeight = 700; // 容器的高度
const buffer = 5; // 缓冲区,提前加载的数据项数量let data = []; // 获取元素
let visibleData = []; // 存储当前可视区域的数据项
let startIndex = 0; // 当前可视区域的起始索引

loopFun() 函数的作用:

// 拿到 num 条数据的索引,生成新数组。
function loopFun(num) {data = Array.from({ length: num }, (_, index) => index);handleScroll();
}
  • Array.from() 静态方法从可迭代或类数组对象创建一个新的浅拷贝的数组实例。

handleScroll() 函数的作用:

function handleScroll() {/** scrollTop 用于获取或设置一个元素的垂直滚动距离 */const scrollTop = container.scrollTop;/*** Math.max() 静态方法返回作为输入参数给出的数字中的最大值* Math.floor() 静态方法始终向下舍入并返回小于或等于给定数字的最大整数** scrollTop / itemHeight 得到当前滚动条所处数据位置* buffer 意味着在可视区域上方和下方各提前加载5个数据项*/const visibleStart = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);/*** Math.min() 静态方法返回作为输入参数给出的数字中的最小者* Math.ceil() 静态方法始终向上舍入并返回大于或等于给定数字的最小整数*/const visibleEnd = Math.min(data.length,visibleStart + Math.ceil(containerHeight / itemHeight) + buffer * 2);startIndex = visibleStart;visibleData = data.slice(visibleStart, visibleEnd);renderVisibleData();}
  1. scrollTop
    scrollTop 是当前滚动条的位置,表示从容器顶部到滚动条当前位置的距离(以像素为单位)。

  2. itemHeight
    itemHeight 是每个数据项的高度(以像素为单位)。假设每个数据项的高度是固定的,例如 50 像素。

  3. scrollTop / itemHeight
    这个表达式计算当前滚动条位置对应的数据项索引。结果是一个浮点数,表示滚动条位置对应的数据项的大致位置。

  4. Math.floor(scrollTop / itemHeight)
    使用 Math.floor 将浮点数向下取整,得到一个整数索引,表示当前滚动条位置对应的数据项的起始索引。

  5. Math.floor(scrollTop / itemHeight) - buffer
    减去 buffer,确保在可视区域上方提前加载 buffer 个数据项。buffer 是一个缓冲区,表示在可视区域外提前加载的数据项数量。例如,buffer 设为 5,意味着在可视区域上方提前加载 5 个数据项。

  6. Math.max(0, …)
    使用 Math.max 确保 visibleStart 不小于 0,防止负索引。如果 Math.floor(scrollTop / itemHeight) - buffer 小于 0,则 visibleStart 会被设置为 0。


renderVisibleData() 函数的作用:

// 处理标签结构及文本的展示
function renderVisibleData() {container.innerHTML = "";visibleData.forEach((item, index) => {const div = document.createElement("div");div.className = "item";div.style.top = (startIndex + index) * itemHeight + "px";div.textContent = `数据-${item}`;container.appendChild(div);});
}

相当于生成了一个 div 标签,加上 class 属性 item

<div class="item">数据-1</div>

然后对这个标签进行循环展示。

{visibleData.map((item, index) => (<div class="item" key={item}>数据-{item}</div>));
}

这一行代码,可以详细说一说:

div.style.top = (startIndex + index) * itemHeight + "px";
  1. div.style.top
    div.style:这是 DOM 元素的 style 属性,它允许你直接访问和修改元素的内联样式。
    top:这是 style 对象的一个属性,用于设置元素的 top CSS 属性。top 属性定义了元素相对于其父容器的顶部边缘的距离。

  2. (startIndex + index) * itemHeight
    startIndex:这是当前可视区域的起始索引,表示第一个可见数据项在整个数据数组中的位置。
    index:这是当前数据项在其可视区域内的索引。例如,如果 visibleData 包含 10 个数据项,index 会从 0 到 9。

  3. itemHeight:这是每个数据项的高度(以像素为单位)。

准确的来说这是用来计算数据项的垂直位置的。

  • startIndex + index:计算当前数据项在整个数据数组中的实际索引。startIndex 是当前可视区域的起始索引,index 是当前数据项在其可视区域内的索引。

  • (startIndex + index) \* itemHeight:将实际索引乘以每个数据项的高度,得到当前数据项的垂直位置(以像素为单位)。

  • 设置 top 属性: div.style.top = (startIndex + index) * itemHeight + ‘px’:将计算得到的垂直位置设置为 div 元素的 top 属性值。这样,每个数据项都会根据其在数据数组中的位置被正确地定位在容器中。

示例:

startIndex = 10;
index = 2;
itemHeight = 50;

计算过程:

startIndex + index = 10 + 2 = 12(startIndex + index) _ itemHeight = 12 _ 50 = 600div.style.top = 600 + 'px' = 600px

因此,这个数据项的 top 属性会被设置为 600px,表示它距离容器顶部 600 像素。

作用:通过这种方式,你可以确保每个数据项在容器中的位置是正确的。即使容器滚动,每个数据项也会根据其在数据数组中的位置被正确地定位,从而实现虚拟滚动的效果。


throttle() 函数的作用:

// 节流处理
function throttle(func, limit) {let inThrottle;return function () {const args = arguments;const context = this;if (!inThrottle) {func.apply(context, args);inThrottle = true;setTimeout(() => (inThrottle = false), limit);}};
}

throttle 函数是一种常用的节流技术,用于限制函数的调用频率。它在处理高频事件(如滚动、窗口调整大小等)时非常有用,可以显著提高性能并减少不必要的计算。

示例:

  • func:需要节流的函数。
  • limit:节流的时间间隔(以毫秒为单位),表示在多少毫秒内只能执行一次 func。
// 100 毫秒后执行函数 handleScroll
throttle(handleScroll, 100);

底部函数调用:

loopFun(1000);

调用 loopFun 函数,生成 1000 个数据项。


const throttledHandleScroll = throttle(handleScroll, 100);

使用 throttle 函数对 handleScroll 进行节流处理,确保 handleScroll 每 100 毫秒最多执行一次。


container.addEventListener("scroll", throttledHandleScroll);

向容器元素添加滚动事件监听器,当容器滚动时,throttledHandleScroll 函数会被调用。


window.addEventListener("beforeunload", () => {container.removeEventListener("scroll", throttledHandleScroll);
});
  • window\.addEventListener('beforeunload', ...):在窗口即将卸载时(例如用户关闭页面或导航到其他页面)触发的事件。

  • container.removeEventListener('scroll', throttledHandleScroll):在页面卸载前移除滚动事件监听器,避免内存泄漏。

相关文章:

虚拟滚动列表如何实现?

highlight: a11y-dark 虚拟滚动列表&#xff0c;虚拟滚动的关键在于只渲染当前视口内可见的数据项&#xff0c;而不是一次性渲染所有数据项。这可以显著提高性能&#xff0c;尤其是在处理大量数据时。 以下是一个完整的虚拟滚动列表的示例代码&#xff1a; <!DOCTYPE htm…...

07_Linux网络配置与管理:命令与工具指南

本系列文章导航&#xff1a;01_Linux基础操作CentOS7学习笔记-CSDN博客 文章目录 网络配置与管理&#xff1a;命令与工具指南1. ping命令2. ifconfig命令3. ip命令4. route命令5. ip route命令6. nslookup命令7. nmcli命令8. nmtui命令9. RHEL7修改网卡名1. 修改网络(会话)配置…...

首个统一生成和判别任务的条件生成模型框架BiGR:专注于增强生成和表示能力,可执行视觉生成、辨别、编辑等任务

BiGR是一种新型的图像生成模型&#xff0c;它可以生成高质量的图像&#xff0c;同时还能有效地提取图像特征。该方法是通过将图像转换为一系列的二进制代码来工作&#xff0c;这些代码就像是图像的“压缩版”。在训练时会遮住一些代码&#xff0c;然后让模型学习如何根据剩下的…...

【Java知识】Java进阶-服务发现机制SPI

文章目录 SPI概述SPI 工作原理 ServiceLoader代码展示简化的 ServiceLoader 类关键点解释使用示例1. 定义服务接口2. 实现服务提供者3. 配置文件4. 加载服务提供者 总结 SPI使用场景1. 数据库驱动2. 日志框架3. 图像处理4. 加密算法5. 插件系统6. 缓存机制示例代码1. 定义服务接…...

多模态技术的协同表现:从文本生成、语音合成到口型同步综合测评

本文是针对多模态对话系统核心技术栈的使用效果和网络测评整理。 测评内容基于用户体验&#xff0c;侧重于从使用者角度出发&#xff0c;讨论实际操作中的体验感受&#xff0c;如技术的易用性、输出效果如文本的连贯性、语音的自然度、口型同步的准确性等。不涉及具体算法架构…...

Java最全面试题->Java主流框架->Srping面试题

Spring面试题 下边是我自己整理的面试题,基本已经很全面了,想要的可以私信我,我会不定期去更新思维导图 哪里不会点哪里 谈谈你对 Spring 的理解? Spring 是一个开源框架,为简化企业级应用开发而生。Spring 可以是使简单的 JavaBean 实现以前只有 EJB 才能实现的功能。…...

参编国家标准需要注意的事项有哪些?

1. 项目相关性&#xff1a; • 选择与自身企业产品、业务或专业领域紧密相关的国家标准进行参编。这样不仅能确保企业在标准制定过程中发挥自身的优势和专长&#xff0c;使参编工作更有实际意义和价值&#xff0c;也有利于企业将标准更好地应用于自身的生产经营活动&#xff0c…...

【Dash】feffery_antd_components 按钮组件的应用

一、feffery_antd_componenet 中的 AntdFloatButton 和 AntdFloatButtonGroup AntdFloatButton 和 AntdFloatButtonGroup 是两个用于创建悬浮按钮和悬浮按钮组的组件。 AntdFloatButton 是单个悬浮按钮组件&#xff0c;它提供了多种属性来定义按钮的外观及行为。AntdFloatBut…...

01 springboot-整合日志(logback-config.xml)

logback-config.xml 是一个用于配置 Logback 日志框架的 XML 文件&#xff0c;通常位于项目的 classpath 下的根目录或者 src/main/resources 目录下。 Logback 提供了丰富的配置选项&#xff0c;可以满足各种不同的日志需求。需要根据具体情况进行配置。 项目创建&#xff0…...

Java最全面试题->计算机基础面试题->计算机网络面试题

计算机网络 下边是我自己整理的面试题&#xff0c;基本已经很全面了&#xff0c;想要的可以私信我&#xff0c;我会不定期去更新思维导图 哪里不会点哪里 1.说一下TCP/IP四层模型 TCP/IP协议是美国国防部高级计划研究局为实现ARPANET互联网而开发的。 网络接口层&#xff…...

VSCode编译器改为中文

1. 通过快捷键设置中文 打开命令面板&#xff1a;按住键盘上的CtrlShiftP组合键&#xff0c;打开命令面板。 输入并设置语言&#xff1a;在命令面板中输入Configure Display Language。 点击Configure Display Language选项。 在弹出的语言选择列表中&#xff0c;选择zh-cn…...

前端开发设计模式——状态模式

目录 一、状态模式的定义和特点 二、状态模式的结构与原理 1.结构&#xff1a; 2.原理&#xff1a; 三、状态模式的实现方式 四、状态模式的使用场景 1.按钮的不同状态&#xff1a; 2.页面加载状态&#xff1a; 3.用户登录状态&#xff1a; 五、状态模式的优点 1.提…...

特种作业操作烟花爆竹试题分享

1.&#xff08;单选题&#xff09;职业卫生研究的是人类从事各种职业劳动过程中的&#xff08; &#xff09;。 A.健康问题 B.环境问题 C.卫生问题 答案:C 2.&#xff08;单选题&#xff09;安全生产事关人民群众的&#xff08; &#xff09;安全&#xff0c;事关改革发展和…...

实现prometheus+grafana的监控部署

直接贴部署用的文件信息了 kubectl label node xxx monitoringtrue 创建命名空间 kubectl create ns monitoring 部署operator kubectl apply -f operator-rbac.yml kubectl apply -f operator-dp.yml kubectl apply -f operator-crd.yml # 定义node-export kubectl app…...

确保Spring Boot定时任务只执行一次方案

在Spring Boot项目中&#xff0c;确保定时任务只执行一次是一个常见的需求。这种需求可以通过多种方式来实现&#xff0c;以下是一些常见的方法&#xff0c;它们各具特点&#xff0c;可以根据项目的实际需求来选择最合适的方法。 1. 使用Scheduled注解并设置极大延迟 一种简单…...

【Python数据可视化】利用Matplotlib绘制美丽图表!

【Python数据可视化】利用Matplotlib绘制美丽图表&#xff01; 数据可视化是数据分析过程中的重要步骤&#xff0c;它能直观地展示数据的趋势、分布和相关性&#xff0c;帮助我们做出明智的决策。在 Python 中&#xff0c;Matplotlib 是最常用的可视化库之一&#xff0c;它功能…...

【最新通知】2024年Cisco思科认证CCNA详解

CCNA现在涵盖安全性、自动化和可编程性。该计划拥有一项涵盖IT职业基础知识的认证&#xff0c;包括一门考试和一门培训课程&#xff0c;助您做好准备。 CCNA培训课程和考试最近面向最新技术和工作岗位进行了重新调整&#xff0c;为您提供了向任何方向发展事业所需的基础。CCNA认…...

监控内容、监控指标、监控工具大科普

在现代信息技术领域&#xff0c;监控技术扮演着至关重要的角色。它帮助我们实时了解系统、网络、应用以及环境的状态&#xff0c;确保它们的安全、稳定和高效运行。以下是对监控内容、监控指标和监控工具的详细科普。 一、监控内容 监控内容是指监控系统所关注和记录的具体信…...

生成文件夹 - python 实现

生成文件夹保存图片和文本等信息。 代码具体实现如下&#xff1a; #-*-coding:utf-8-*- # date:2021-04-13 # Author: DataBall - XIAN # Function: 生成文件夹import os if __name__ "__main__":path "./dataset"if not os.path.exists(path): # 如果…...

快速了解学会python基础语言及IDLE 提供的常用快捷键

&#x1f600;前言 本篇博文是关于python的基础语言介绍及IDLE 提供的常用快捷键&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...