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

在前端开发中,当需要展示大量数据时,如何保持页面的流畅性是一个挑战。传统的滚动方式会将所有数据一次性渲染到页面,这可能导致页面加载缓慢甚至崩溃。而虚拟滚动技术能够解决这个问题,它只渲染可视区域内的数据,从而提升页面性能。本文将详细解析一个基于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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值