【vue】实现高性能虚拟滚动的Vue代码解析

news2024/9/24 7:21:30

在前端开发中,当需要展示大量数据时,如何保持页面的流畅性是一个挑战。传统的滚动方式会将所有数据一次性渲染到页面,这可能导致页面加载缓慢甚至崩溃。而虚拟滚动技术能够解决这个问题,它只渲染可视区域内的数据,从而提升页面性能。本文将详细解析一个基于Vue框架实现的虚拟滚动示例代码,让我们一步步来看看其中的奥秘。

图例:在这里插入图片描述

HTML 结构和基本样式

首先,让我们看一下HTML结构和基本的样式设置。这段代码主要定义了用于展示纵向和横向滚动列表的两个容器,以及它们的样式设置。

<div id="app">
        <div>纵向滚动数据:{{ clist }}</div>
        <!-- 显示纵向滚动的数据列表 -->

        <div class="box" :style="`height:${viewH}px;overflow-y:scroll;`" @scroll="handleScroll">
            <!-- 设置可滚动的外部容器,并监听滚动事件 -->
            <ul>
                <li :style="`transform:translateY(${offsetY}px); height:${itemH}px;`" v-for='i in clist'
                    :key="i">{{i}}
                </li>
                <!-- 使用虚拟滚动技术,只渲染可视区域内的列表项 -->
            </ul>
        </div>
        <div>横向滚动数据:{{ clist2 }}</div>
        <!-- 显示横向滚动的数据列表 -->

        <div class="box2" :style="`width:${viewW}px;overflow-x:scroll;`" @scroll="handleScroll2">
            <!-- 设置可滚动的外部容器,并监听滚动事件 -->
            <div style="display: flex;">
                <!-- 使用flex布局,用于横向排列列表项 -->
                <div :style="`transform:translateX(${offsetX}px); width:${itemW}px;flex-shrink: 0;`"
                    v-for='i in clist2' :key="i">{{i}}
                </div>
                <!-- 使用虚拟滚动技术,只渲染可视区域内的列表项 -->
            </div>
        </div>
    </div>

在样式部分,通过<style>标签设置了一些基本样式,将所有元素的内外边距、列表样式、盒模型等进行了调整,以便后续的布局和展示。

数据初始化和Vue实例

接下来,让我们来看一下数据的初始化和Vue实例的创建。这部分代码主要进行了数据初始化,包括一个包含了一万条数据的数组,并通过Vue实例将数据绑定到页面。

 let list = []
        for (let index = 0; index < 10000; index++) {
            list.push(index)
        }
        // 创建一个包含10000个元素的数组

        new Vue({
            el: '#app',
            data() {
                return {
                    list, // 上万条总数据
                    clist: [], // 页面展示的纵向滚动数据
                    clist2: [], // 页面展示的横向滚动数据
                    viewH: 500, // 外部纵向滚动容器的高度
                    itemH: 60, // 单项的高度
                    scrollH: '', // 整个滚动列表的高度
                    showNum: '', // 可视区内显示的纵向列表项数量
                    showNum2: '', // 可视区内显示的横向列表项数量
                    offsetY: 0, // 纵向滚动时的偏移量
                    offsetX: 0, // 横向滚动时的偏移量
                    viewW: 300, // 外部横向滚动容器的宽度
                    itemW: 60, // 横向列表项的宽度
                };
            },
            }) 

在Vue实例中,通过data选项定义了一系列数据,包括总数据列表、展示的纵向和横向滚动数据、外部容器的高度和宽度、单项的高度和宽度等。这些数据将会在后续的滚动事件中使用。

纵向滚动虚拟列表

现在,我们来看一下如何实现纵向虚拟滚动列表。在这一部分,代码通过监听滚动事件,动态计算偏移量和显示的数据范围,从而实现了虚拟滚动的效果。

handleScroll(e) {
                    // 纵向滚动事件处理函数
                    if (new Date().getTime() - this.lastTime > 10) {
                        let scrollTop = e.target.scrollTop; // 获取滚动的高度
                        this.offsetY = scrollTop - (scrollTop % this.itemH);
                        // 计算偏移量,用于虚拟滚动的位置调整
                        this.clist = this.list.slice(
                            Math.floor(scrollTop / this.itemH),  
                            Math.floor(scrollTop / this.itemH) + this.showNum
                        );
                        // 根据滚动位置更新显示的列表项数据
                        this.lastTime = new Date().getTime();
                    }
                },

handleScroll方法中,通过获取滚动的高度来计算偏移量,以及通过计算偏移量来确定显示的数据范围。这样,在滚动时只渲染可视区域内的数据,大大提升了性能。注意,代码中加入了时间间隔判断,以确保滚动频率不会过高。

横向滚动虚拟列表

类似地,让我们来看一下如何实现横向虚拟滚动列表。这部分代码与纵向滚动的实现类似,只是方向和数据计算稍有不同。

  handleScroll2(e) {
                    // 横向滚动事件处理函数
                    if (new Date().getTime() - this.lastTime2 > 10) {
                        let scrollWidth = e.target.scrollLeft; // 获取滚动的宽度
                        this.offsetX = scrollWidth - (scrollWidth % this.itemW);
                        // 计算偏移量,用于虚拟滚动的位置调整
                        this.clist2 = this.list.slice(
                            Math.floor(scrollWidth / this.itemW),
                            Math.floor(scrollWidth / this.itemW) + this.showNum2
                        );
                        // 根据滚动位置更新显示的列表项数据
                        this.lastTime2 = new Date().getTime();
                    }
                },

handleScroll2方法中,通过获取滚动的宽度来计算横向偏移量,然后再根据偏移量计算显示的数据范围。这里同样也加入了时间间隔判断,以保证滚动的流畅性。

总结

通过以上的代码分析,我们深入了解了基于Vue实现的高性能虚拟滚动技术。这项技术通过动态计算偏移量和显示的数据范围,使得页面在渲染大量数据时能够保持流畅性。特别是在滚动事件中加入时间间隔判断,进一步优化了滚动性能。

虽然本文只是简单介绍了虚拟滚动的实现思路,但它背后的原理和技术值得我们深入学习和探讨。通过这个示例,我们不仅可以提升页面性能,还可以更好地理解前端渲染机制和优化策略。

希望本文对你理解和掌握虚拟滚动技术有所帮助!如果你有任何疑问或者想进一步深入讨论,欢迎在评论区留言。感谢阅读!
完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <!-- 省略了一些meta和title标签 -->
    <style>
        /* 基本样式设置 */
    </style>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.min.js"></script>
    <!-- 引入Vue库 -->
</head>

<body>
    <div id="app">
        <div>纵向滚动数据:{{ clist }}</div>
        <!-- 显示纵向滚动的数据列表 -->

        <div class="box" :style="`height:${viewH}px;overflow-y:scroll;`" @scroll="handleScroll">
            <!-- 设置可滚动的外部容器,并监听滚动事件 -->
            <ul>
                <li :style="`transform:translateY(${offsetY}px); height:${itemH}px;`" v-for='i in clist'
                    :key="i">{{i}}
                </li>
                <!-- 使用虚拟滚动技术,只渲染可视区域内的列表项 -->
            </ul>
        </div>
        <div>横向滚动数据:{{ clist2 }}</div>
        <!-- 显示横向滚动的数据列表 -->

        <div class="box2" :style="`width:${viewW}px;overflow-x:scroll;`" @scroll="handleScroll2">
            <!-- 设置可滚动的外部容器,并监听滚动事件 -->
            <div style="display: flex;">
                <!-- 使用flex布局,用于横向排列列表项 -->
                <div :style="`transform:translateX(${offsetX}px); width:${itemW}px;flex-shrink: 0;`"
                    v-for='i in clist2' :key="i">{{i}}
                </div>
                <!-- 使用虚拟滚动技术,只渲染可视区域内的列表项 -->
            </div>
        </div>
    </div>
    <script>
        let list = []
        for (let index = 0; index < 10000; index++) {
            list.push(index)
        }
        // 创建一个包含10000个元素的数组

        new Vue({
            el: '#app',
            data() {
                return {
                    list, // 上万条总数据
                    clist: [], // 页面展示的纵向滚动数据
                    clist2: [], // 页面展示的横向滚动数据
                    viewH: 500, // 外部纵向滚动容器的高度
                    itemH: 60, // 单项的高度
                    scrollH: '', // 整个滚动列表的高度
                    showNum: '', // 可视区内显示的纵向列表项数量
                    showNum2: '', // 可视区内显示的横向列表项数量
                    offsetY: 0, // 纵向滚动时的偏移量
                    offsetX: 0, // 横向滚动时的偏移量
                    viewW: 300, // 外部横向滚动容器的宽度
                    itemW: 60, // 横向列表项的宽度
                };
            },
            mounted() {
                // 初始化操作在挂载后执行
                this.scrollH = this.list.length * this.itemH;
                // 计算整个滚动列表的高度
                this.showNum = Math.floor(this.viewH / this.itemH) + 4;
                // 计算可视区内能够容纳的纵向列表项数量
                this.clist = this.list.slice(0, this.showNum);
                // 初始化显示的纵向列表项数据
                this.lastTime = new Date().getTime();
                this.scrollW = this.list.length * this.itemW;
                // 计算整个滚动列表的宽度
                this.showNum2 = Math.floor(this.viewW / this.itemW) + 4;
                // 计算可视区内能够容纳的横向列表项数量
                this.clist2 = this.list.slice(0, this.showNum2);
                // 初始化显示的横向列表项数据
                this.lastTime2 = new Date().getTime();
            },
            methods: {
                handleScroll(e) {
                    // 纵向滚动事件处理函数
                    if (new Date().getTime() - this.lastTime > 10) {
                        let scrollTop = e.target.scrollTop; // 获取滚动的高度
                        this.offsetY = scrollTop - (scrollTop % this.itemH);
                        // 计算偏移量,用于虚拟滚动的位置调整
                        this.clist = this.list.slice(
                            Math.floor(scrollTop / this.itemH),  
                            Math.floor(scrollTop / this.itemH) + this.showNum
                        );
                        // 根据滚动位置更新显示的列表项数据
                        this.lastTime = new Date().getTime();
                    }
                },
                handleScroll2(e) {
                    // 横向滚动事件处理函数
                    if (new Date().getTime() - this.lastTime2 > 10) {
                        let scrollWidth = e.target.scrollLeft; // 获取滚动的宽度
                        this.offsetX = scrollWidth - (scrollWidth % this.itemW);
                        // 计算偏移量,用于虚拟滚动的位置调整
                        this.clist2 = this.list.slice(
                            Math.floor(scrollWidth / this.itemW),
                            Math.floor(scrollWidth / this.itemW) + this.showNum2
                        );
                        // 根据滚动位置更新显示的列表项数据
                        this.lastTime2 = new Date().getTime();
                    }
                },
            },
        });
    </script>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/930926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue2向Vue3过度Vuex核心概念actions

目录 1 核心概念 - actions1.定义actions2.组件中通过dispatch调用 2 辅助函数 -mapActions 1 核心概念 - actions state是存放数据的&#xff0c;mutations是同步更新数据 (便于监测数据的变化, 更新视图等, 方便于调试工具查看变化)&#xff0c; actions则负责进行异步操作 说…

用Python写一个武侠游戏

前言 在本教程中&#xff0c;我们将使用Python写一个武侠类的游戏&#xff0c;大的框架全部搭好了&#xff0c;很多元素都可以自己添加&#xff0c;让游戏更丰富 &#x1f4dd;个人主页→数据挖掘博主ZTLJQ的主页 个人推荐python学习系列&#xff1a; ☄️爬虫JS逆向系列专栏 -…

PHP自己的框架cookie()使用(完善篇七)

1、PHP自己的框架cookie() 2、cookie类&#xff08;CookieBase.php&#xff09; <?php class CookieBase {/*** 设置cookie*/public static function set($name, $value, $expire 3600, $path , $domain , $secure false, $httponly false) {setcookie($name, $valu…

Verilog 实现超声波测距

Verilog 实现超声波测距 教学视频&#xff1a; https://www.bilibili.com/video/BV1Ve411x75W?p33&spm_id_frompageDriver&vd_source19ae31dff4056e52d2729a4ca212602b 超声波测距原理 参考资料&#xff1a;STM32的超声波测距程序_超声波测距stm32程序_VaderZhang的…

cs231n assignment3 q5 Self-Supervised Learning for Image Classification

文章目录 嫌墨迹直接看代码Q5 Self-Supervised Learning for Image Classificationcompute_train_transform CIFAR10Pair.__getitem__()题面解析代码输出 simclr_loss_naive题面解析代码输出 sim_positive_pairs题面解析代码输出 compute_sim_matrix题面解析代码输出 simclr_lo…

37、springboot 为 spring mvc 提供的自动配置及对自动配置的一些自定义定制(大体思路)

springboot 为 spring mvc 提供的自动配置及对自动配置的一些自定义定制&#xff08;大体思路&#xff09; ★ Spring Boot主流支持两个MVC框架&#xff1a; Spring MVC&#xff08;基于Servlet&#xff09; Spring WebFlux&#xff08;基于Reactive&#xff0c;属于响应式AP…

开源双语对话语言模型 ChatGLM-6B 本地私有化部署

本文首发于&#xff1a;https://www.licorne.ink/2023/08/llm-chatglm-6b-local-deploy/ ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级…

人员跌倒检测识别预警

人员跌倒检测识别预警系统通过pythonopencv深度学习网络模型架构&#xff0c;人员跌倒检测识别预警系统实时监测老人的活动状态&#xff0c;通过图像识别和行为分析算法&#xff0c;对老人的姿态、步态等进行检测和识别&#xff0c;一旦系统检测到跌倒事件&#xff0c;立即发出…

Vue2向Vue3过度Vuex核心概念state状态

目录 1 核心概念 - state 状态1.目标2.提供数据3.访问Vuex中的数据4.通过$store访问的语法5.代码实现5.1模板中使用5.2组件逻辑中使用5.3 js文件中使用 2 通过辅助函数 - mapState获取 state中的数据1.第一步&#xff1a;导入mapState (mapState是vuex中的一个函数)2.第二步&am…

Dubbo—流量管控

此任务基于一个简单的线上商城微服务系统演示了 Dubbo 的流量管控能力。 线上商城的架构图如下&#xff1a; 系统由 5 个微服务应用组成&#xff1a; Frontend 商城主页&#xff0c;作为与用户交互的 web 界面&#xff0c;通过调用 User、Detail、Order 等提供用户登录、商品…

为什么使用Nacos而不是Eureka(Nacos和Eureka的区别)

文章目录 前言一、Eureka是什么&#xff1f;二、Nacos是什么&#xff1f;三、Nacos和Eureka的区别3.1 支持的CAP3.2连接方式3.3 服务异常剔除3.4 操作实例方式 总结 前言 为什么如今微服务注册中心用Nacos相对比用Eureka的多了&#xff1f;本文章将介绍他们之间的区别和优缺点…

推荐前 6 名 JavaScript 和 HTML5 游戏引擎

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建3D应用场景 事实是&#xff0c;自从引入JavaScript WebGL API以来&#xff0c;现代浏览器具有直观的功能&#xff0c;使它们能够渲染更复杂和复杂的2D和3D图形&#xff0c;而无需依赖第三方插件。 你可以用纯粹的JavaScript开…

Nuxt3打包部署到Linux(node+pm2安装和运行步骤+nginx代理)

最近&#xff0c;我们项目组的工作接近尾声&#xff0c;需要把项目部署上线。由于前端第一次使用Nuxt3框架&#xff0c;后端也是第一次部署Nuxt3项目&#xff0c;所以刚开始出现了很多问题。在我上网搜索很多教程后&#xff0c;得到了基本的流程。 1.服务器安装node.js环境 N…

Linux常用命令_文件搜索命令

文章目录 1. 文件搜索命令find2. 其他搜索命令2.1 文件搜索命令&#xff1a;locate2.2 文件搜索命令&#xff1a;which2.3 文件搜索命令&#xff1a;whereis2.4 文件搜索命令&#xff1a;grep 1. 文件搜索命令find 2. 其他搜索命令 2.1 文件搜索命令&#xff1a;locate 作为f…

c语言练习题30:判断一个数是否为2^n

判断一个数是否为2^n 思路&#xff1a;2^n中只有一个1故可以通过n&(n-1)是否为0来判断。 代码&#xff1a;

Android 之 WindowManager (窗口管理服务)

本节引言&#xff1a; 本节给大家带来的Android给我们提供的系统服务中的——WindowManager(窗口管理服务)&#xff0c; 它是显示View的最底层&#xff0c;Toast&#xff0c;Activity&#xff0c;Dialog的底层都用到了这个WindowManager&#xff0c; 他是全局的&#xff01;该类…

用MFC打开外部程序

在MFC&#xff08;Microsoft Foundation Classes&#xff09;中&#xff0c;你可以使用ShellExecute函数来打开Notepad并加载指定的文件。ShellExecute函数是Windows API的一部分&#xff0c;它可以执行与操作系统相关的操作&#xff0c;例如打开文件、运行程序等。 以下是在M…

VBJSON报错:缺少:语句结束

项目中使用JSON库VBJSON时报错&#xff1a; 编译错误&#xff1a;缺少&#xff1a;语句结束 cJSONScript和cStringBuilder报相同的错误&#xff0c;都在第一行: VERSION 1.0 CLASS 研究了半天没啥结果&#xff0c;之前使用这个库的时候没有什么问题&#xff0c;所以判定是当前…

51WORLD李熠:地球克隆计划就像攀登珠峰

提起数字化这个词&#xff0c;相信大家早已耳熟能详。然而数字化世界的意义是什么&#xff1f;它又给我们带来了什么&#xff1f;是让我们的真实世界更加美好&#xff1f;还是让我们沉迷于虚拟世界&#xff1f; 对于以上这些问题&#xff0c;51WORLD创始人兼CEO李熠给出的答案是…

基于Java+SpringBoot+Vue前后端分离医院资源管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…