仿掘金项目,虚拟列表实现📜 | 青训营笔记

839 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的的第4天

一 前言

在掘金官网的主页,我们如果一直下拉页面,会发现文章列表是拉不完的。原因是每次页面触底,都会使得浏览器发送一次请求,将文章列表延长,但是随着文章列表的逐渐增长,浏览器的运算负担也会加剧,滚动页面也会变得卡顿起来。而 虚拟列表 可以有效的解决这个问题,神奇之就在于只将视窗内的部分渲染出来,其余部分你暂时看不见也就先不渲染了。

(本项目基于Vue2开发,相关代码呈现的语法为Vue)

仿掘金项目github地址 (github.com/IamTrust/ju…)

二 实现原理

Snipaste_2022-08-16_21-37-53.png

实现思路从上图中可以一目了然,无非就是几个重要的数据要获取到:

  • 开始列表元素的索引
  • 结束列表元素的索引
  • 展示内容的视图高度(像掘金的就是整个浏览器的高度)
  • 单个列表元素的高度
  • 上滚动区域的高度

数据源准备

data() {
        return {
            articleInfoList: [],   //存放文章列表数据的数组
            itemHeight: 136,       //每一列的高度
            showNum: 10,           //视窗内显示几条数据
            start: 0,              //开始索引
            end: 10,               //结束索引
        }
},

1. 文章列表结构

Snipaste_2022-08-16_22-03-27.png

<div class="contents__list" ref="scrollBar">
            <div class="list__header" ></div>
            
            <div class="list__content">
                <ul class="article__list" ref="list">
                    <li v-for="article in showList" :key="article.articleId" class="list__item"></li>
                </ul>
            </div>
</div>

2. 计算开始和结束的索引值

// 需要放在 methods 里
// 计算文章列表呈现在页面上开头和结尾的位置
scrollListener(scrollTop){
    //计算总的数据需要的高度,构造滚动条高度
    this.$refs.scrollBar.style.height = this.itemHeight * this.articleInfoList.length + 'px';
    //开始的数组索引
    let first = Math.floor(scrollTop / this.itemHeight) - 1;
    this.start = first<0 ? 0 : first;
    
    //结束索引
    this.end = this.start + this.showNum;
    //计算上滚动区域的高度
    this.$refs.list.style.marginTop = this.start * this.itemHeight + 'px';
},

这个函数需要在Vue生命周期函数created中被创建滚动条监听事件

created() {
        window.addEventListener("scroll", this.lasyLoading);
},

// 需要放在 methods 里,
lasyLoading() {
            let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            /* 
                这里是数据请求的代码
            */
            this.scrollListener(scrollTop); 
},

3. 计算出展示在视窗内的文章列表

computed: {
        // 显示的数组,用计算属性计算
        // 在上面 li标签里循环的是 showList
        showList(){  return this.articleInfoList.slice(this.start, this.end);  }
},

三 参考文章

虚拟列表,我真的会了!!! - 掘金 (juejin.cn)