虚拟滚动实现

虚拟滚动实现

废话少说,先上代码,再聊原理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>虚拟滚动实现</title>
    <script src="vue.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
        .view-container {
            overflow: hidden;
            padding: 5px;
            margin: 5px;
            border: 1px solid #ccc;
        }
        .list-scroll-wrapper {
            height: 100%;
            overflow: auto;
        }
        .row-wrapper {
            height: 30px;
            line-height: 30px;
        }
        .virtual-container {
            position: relative;
        }
    </style>
    
</head>
<body>
    <div id="app">
        <div class="view-container" :style="{height: viewHeight + 'px'}"> <!-- 最外层的可视 -->
            <div class="list-scroll-wrapper" @scroll="handleScroll"> <!-- 滚动层 -->
                <div class="virtual-container" :style="{height: virtualHeight + 'px'}"> <!-- 虚拟高度层 -->
                    <div style="position: absolute; left: 0;" :style="{top: viewTop + 'px'}"> <!-- 绝对定位,显示数据,否则会随着滚动而滚动 -->
                        <p v-for="item in list" :key="item.id" class="row-wrapper"> {{item.val}}</p> <!-- 实际显示的表格 -->
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script>
        // 目标:加载10W行数据
        // 实现:采用虚拟滚动技术
        // 1.创建显示的列表
        // 2.控制显示的高度
        // 3.根据数据虚拟出一个高度
        // 4.虚拟的高度外包一层,用于实现滚动
        // 5.实际的显示列表采用绝对定位,实时改变top,保证一直可视
        new Vue({
            el: '#app',
            data: {
                data: [], // 所有数据
                list: [], // 当前显示的可视数据
                rowHeight: 30, // 行高
                viewHeight: 300, // 可视列表高度
                virtualHeight: 300, // 虚拟的高度,
                viewTop: 0,
            },
            created() {
                this.mockData()
                this.refreshList()
            },
            mounted() {
                this.virtualHeight = this.data.length * this.rowHeight
            },
            methods: {
                mockData() { // 造数据
                    const data = []
                    for(let i=0; i<100000; i++) {
                        data.push({ 
                            id: i,
                            val: 'data-' + i
                        })
                    }
                    this.data = data
                },
                refreshList(start = 0, end = 20) { // 根据传入的值去渲染数据    
                    const list = []
                    end = end < this.data.length ? end : this.data.length
                    for(let i=start; i<end; i++) {
                        list.push(this.data[i])
                    }
                    this.list = list
                },
                handleScroll(e) {
                    const scrollTop = e.target.scrollTop
                    this.viewTop = scrollTop
                    // 根据滚动位置进行计算显示的数据
                    const start = parseInt(scrollTop / this.rowHeight) + 1
                    this.refreshList(start, start + 20)
                }
                
            }
        })
    </script>
</body>
</html>

理论研究

简单来说就是通过实际的数据量,然后根据数据来虚拟出一个虚拟高度

然后通过监测这个虚拟高度的滚动高度来动态设置显示的数据

由于显示的数据都在内存,页面渲染的元素只有可视区域的元素,所以理论上来讲能显示多少数据取决于客户端的内存

不过由于是一值滚动的,所以需要固定可视的列表,否则会随着滚动而滚动

固定显示列表可以采用绝对定位,不过这样外面就需要设置一个相对定位

也可以用采用css3的transformY去实现

最后,具体可以查看源码

这里只作技术攻关实现,更多细节请自行实现吧

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
虚拟滚动是一种优化长列表渲染的技术,能够有效地提高大型列表的性能。以下是一个实现虚拟滚动的示例代码,使用了Vue.js框架: ``` <template> <div class="virtual-scroll" ref="scrollArea" @scroll="handleScroll"> <div :style="{height: totalHeight + 'px'}"> <div v-for="(item, index) in visibleItems" :key="index" :style="{transform: 'translateY(' + item.top + 'px)'}"> {{ item.content }} </div> </div> </div> </template> <script> export default { data() { return { itemHeight: 50, // 每个列表项的高度 totalHeight: 0, // 列表总高度 visibleCount: 10, // 可见的列表项个数 scrollTop: 0, // 滚动条距离顶部的距离 items: [], // 列表数据 visibleItems: [], // 可见的列表项 } }, mounted() { // 初始化列表数据 this.items = [...Array(10000).keys()].map(i => ({ id: i, content: 'Item ' + i, })) // 计算列表总高度 this.totalHeight = this.items.length * this.itemHeight // 初始化可见的列表项 this.updateVisibleItems() }, methods: { updateVisibleItems() { // 计算可见区域的起始索引和结束索引 const startIndex = Math.floor(this.scrollTop / this.itemHeight) const endIndex = Math.min(startIndex + this.visibleCount, this.items.length) // 根据可见区域更新可见的列表项 this.visibleItems = this.items.slice(startIndex, endIndex).map((item, index) => ({ id: item.id, content: item.content, top: (startIndex + index) * this.itemHeight, })) }, handleScroll() { // 更新滚动条距离顶部的距离 this.scrollTop = this.$refs.scrollArea.scrollTop // 更新可见的列表项 this.updateVisibleItems() }, }, } </script> ``` 该示例代码实现了一个包含10000个列表项的虚拟滚动列表。当用户滚动列表时,只渲染可见区域内的列表项,而非全部列表项,从而提高了性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值