无限滚动加载算是一个比较常见的功能了,今天以原生js的形式分析一下原理,一般来说,要实现无限滚动加载常见的有以下两种方法。
监听滚动事件
这一种兼容性比较强,但是处理较为繁琐,有时还要搭配防抖一起使用,前置知识为 clientHeight :表示外围div的高度,即可视高度 offsetHeight /scrollHeight :表示内容的高度 scrollTop :表示滚动条可以滚动的高度,举个例子,比如有一个div,它的高度是100px,那么clientHeight=100px;比如这个div 里面的的内容很多,内容的高度为200px,那么offsetHeight = 200px,就是说我们只能看到100px的内容,还有100px的内容是看不到的,只能通过滚动条拉动来查看,scrollTop的范围在[0,100]之间,当滚动条顶部的位置是100px时就是说明滚动条拉到底了。
核心代码如下
function touchScroll() {
let offsetHeight = Math.max(box.scrollHeight,box.offsetHeight); // 内容高度
let clientHeight = window.innerHeight || document.documentElement.clientHeight || box.clientHeight || 0; //视窗高度
let scrollTop = window.pageYOffset || document.documentElement.scrollTop || box.scrollTop || 0; //滚动条滚动高度
return (offsetHeight - clientHeight - scrollTop)
}
window.onscroll=function(){
let touchScroll = this.touchScroll()
if(touchScroll < 0) {
// 发送请求加载
console.log('我到底啦')
}
};
实际效果如下
windowOnscroll.gif
上面的那种适用于全屏下拉加载,所以直接监听 window 上面的 onscroll 事件即可,但是大部分时候页面都不是那么简单的,更多的时候是嵌套加载,
那么这个时候就不能监听 window 了,这个时候需要直接监听DOM上的onscroll事件了,核心代码如下
box.addEventListener('scroll', function (e) {
let offsetHeight = Math.max(this.scrollHeight, this.offsetHeight); // 内容高度
if (offsetHeight - this.clientHeight - this.scrollTop < 10) {
console.log("我到底啦")
}
});
实际效果如下
boxOnscroll.gif
elementui中的InfiniteScroll组件也是这么处理的,不过它是结合着防抖一起做的
elementui.png
IntersectionObserver API
IntersectionObserver 是16年发布的Chrome 51上新出的API,可以自动"观察"元素是否可见 上面的源码就可以简化为下面这几行:
const bottomBox = document.getElementById("bottom-box")
const io = new IntersectionObserver(entries => {
const isIntersecting = entries.find((entry) => {
console.log(entry.isIntersecting)
})
})
io.observe(bottomBox)
效果如图所示
IntersectionObserverAPI.gif
在嵌套滚动中的使用方法也是一样的,效果如下
IntersectionObserver-1.gif
很明显,在使用上,我们对比第一种方法,第二种方法简直便捷的过分,既不需要计算,更不需要防抖之类的操作,详细使用方法如下:
const io = new IntersectionObserver(callback, option);
IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(可选)
// 开始观察
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect()
最后是兼容性,目前主流的pc端浏览器已全面支持(ie除外,不过它的profile现在也出来了,详见github),大家可以放心使用
mdn-IntersectionObserver.png