本文详解如何通过判断scrollTop、clientHeight和scrollHeight实现滚动到底部自动加载数据。提供jQuery与原生JS两种实现方案,解析核心属性含义及代码逻辑,适用于图片瀑布流或列表数据的无限加载场景。
滚动加载数据实现原理
许多网站采用瀑布流图片布局,通过动态加载图片提升用户体验并降低服务器压力。例如在QQ空间浏览时,下拉至底部会自动加载剩余日志或说说。本文将介绍这种效果的实现思路及JavaScript控制动态加载的具体代码。
以下代码主要处理滚动条下拉时的加载事件,无论是加载图片还是获取记录数据,均可适用。
引入jQuery库后,可以使用如下方式实现:
jQuery实现方案
$(window).scroll(function () {
var scrollTop = $(this).scrollTop();
var scrollHeight = $(document).height();
var windowHeight = $(this).height();
if (scrollTop + windowHeight == scrollHeight) {
//此处是滚动条到底部时候触发的事件,在这里写要加载的数据,或者是拉动滚动条的操作
//var page = Number($("#redgiftNextPage").attr('currentpage')) + 1;
//redgiftList(page);
//$("#redgiftNextPage").attr('currentpage', page + 1);
}
});
核心属性解析
代码解析:
判断滚动条是否到达底部,依赖于DOM的三个属性:scrollTop、clientHeight和scrollHeight。
- scrollTop表示滚动条在Y轴方向上的滚动距离。
- clientHeight表示内容可视区域的高度。
- scrollHeight表示内容可视区域的高度加上因溢出而产生的滚动距离。
根据上述属性定义,滚动条到达底部的条件为:scrollTop + clientHeight 等于 scrollHeight。
若使用纯JavaScript实现,代码如下:
原生JavaScript实现方案
window.onscroll = function() {
var scrollTop = document.body.scrollTop;
var offsetHeight = document.body.offsetHeight;
var scrollHeight = document.body.scrollHeight;
if (scrollTop == scrollHeight - offsetHeight) {
page++;
loadList(page);
}
};
function loadList(page) {
page = page || 1;
if (isLoad) {
getJSON('/forum.php?mod=hot&page=' + page).then(function(data) {
if (data.code == 200) {
data = data.data;
if (data && Object.keys(data).length > 0) {
for (var k in data) {
var v = data[k];
detailTemplate = detailTemplate.cloneNode(true);
var userInfoObj = detailTemplate.getElementsByClassName('user-info')[0];
userInfoObj.getElementsByClassName('name')[0].innerText = v.author;
userInfoObj.getElementsByClassName('avatar')[0].src = v.avatar;
userInfoObj.getElementsByClassName('post-time')[0].innerHTML = v.lastpost;
detailTemplate.getElementsByClassName('title')[0].innerText = v.subject;
detailTemplate.getElementsByClassName('desc')[0].innerText = v.subject;
var extInfoObj = detailTemplate.getElementsByClassName('ext-info')[0];
extInfoObj.getElementsByClassName('from')[0].innerText = v.fname;
extInfoObj.getElementsByClassName('view-time')[0].innerText = v.views;
postListObj.appendChild(detailTemplate);
}
} else {
isLoad = false;
}
} else {
isLoad = false;
}
}, function(status) {
console.log('Something went wrong, status is ' + status);
});
}
}