这是我参与「第四届青训营 」笔记创作活动的第2天
前言
在本次的青训营活动中,我们小组选择的项目为“仿掘金官网”,从字面意思上来看,就是要求我们要尽可能像的模仿掘金官网,尤其要实现以下两点:
- 首页文章列表的无限滚动
- 文章页面toc高亮和自动标记
本篇文章主要介绍实现首页文章列表的无限滚动的方法,供大家参考~
分析
所谓无限滚动,可以分为两步: 第一步:滚动到页面底部; 第二步:加载新内容。
于是这里有一个关键问题:如何判断滚动到了页面底部?
翻阅了很多资料,都是在说使用scrollHeight、clientHeight、scrollHeight三者之间的关系进行判断。
以下三个概念摘自MDN,图片源自MDN,自己加了一些标注。
scrollHeight这个只读属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。
clientHeight这个属性是只读属性,对于没有定义 CSS 或者内联布局盒子的元素为 0,否则,它是元素内部的高度 (单位像素),包含内边距,但不包括水平滚动条、边框和外边距。
scrollTop值是这个元素的内容顶部(卷起来的)到它的视口可见内容(的顶部)的距离的度量。
三者之间的关系大致如下图所示:
是不是就可以针对我们的列表,用滚上去了多少+能显示多少(就是上图左半部分)和 整个本身的大小(上图右半部分)比较一下,当左边能打过右边时,就是到底了呢?
答案是:错了一半。
错了一半,是因为:没有垂直滚动条的情况下,scrollHeight 值与元素视图填充所有内容所需要的最小值clientHeight相同。
为什么呢?我们来看一下MDN上面的例子:
可以看到,这个例子中的文本框,自身是带着垂直滚动条的。 但是我们页面中的列表,由于没有给其指定一个height,一般不会自己带一个滚动条(通常是整个页面带一个滚动条),这套方案不能直接用,用了就会出现“为什么我滚动到底部了但是却没有判断成功”的问题。
实现
我们所要实现的,是当页面拉到底部的时候,让他自动加载。但是,请回过头来看看上面几段加粗的部分,都是在针对列表取他们的相关属性,又恰巧没有垂直滚动条的情况下,scrollHeight 值与元素视图填充所有内容所需要的最小值clientHeight相同,当然是行不通的。
因此我们只要去获取页面的相关属性,用页面的相关属性去判断,当然也就能实现当页面拉到底部的时候,让他自动加载咯。
上文提到,可以使用滚上去了多少+能显示多少和整个本身的大小比较一下这条路子进行判断,但是这里,我们可以用更巧妙的方式来判断:
Element.getBoundingClientRect()提供了元素的大小及其相对于视口的位置,如下图所示:
我们主要用到其中的bottom属性,返回了一个元素的底部到整个页面视口上边沿的距离。进而我们可以这么来判断:
当元素底部距离上边沿一定距离时,就触发加载函数。而所谓的一定距离,是和我们的视口的大小是有关的,如下图所示。
如果某一时刻,①+③>②了,说明也快拉到底了,此时应该去加载了。
三个部分数值的获取可用下面的代码:
const windowHeight = window.innerHeight; //获取窗口高度,对应上图中的①
const bottom = [某个Element].getBoundingClientRect().bottom; //list元素底部到屏幕顶部的距离,对应上图中的②
const distance = 70; //对应上图中的③,这个阈值是我们自己设定的
进而可以直接根据windowHeight + distance和distance的关系来判断当前列表是否已触底。
最核心的部分至此已经解决了。再说细一些,无非是把判断的代码放到onscroll对应的处理函数中,一旦符合条件,触发数据加载函数即可。
欢迎大家批评指正~!