在手机端浏览网页时,经常使用一个功能,当我们浏览京东或者淘宝时,页面滑动到底部,我们看到数据自动加载到列表。之前并不知道这些功能是怎么实现的,于是自己在PC浏览器上模拟实现这样的功能。先看看浏览效果:
当滚动条滚动到页面底部时,提示“正在加载…”。
当页面已经加载了所有数据后,滚动到页面底部会提示“数据已加载到底了”:
实现数据无限加载的过程大致如下:
1.滚动条滚动到页面底部。
2.触发ajax加载,把请求返回的数据加载到列表后面。
如何判断滚动条是否滚动到页面底部?我们可以设置一个规则:当滚动条的滚动高度和整个文档高度相差不到20像素,则认为滚动条滚动到页面底部了:
文档高度 - 视口高度 - 滚动条滚动高度 < 20
要通过代码实现这样的判断,我们必须要了解上面的这些高度通过哪些代码获取?可以参考我之前写的一篇“HTML元素坐标定位,这些知识点得掌握”。
上面的判断,我封装了一个方法:
02 |
function isScrollToPageBottom(){ |
04 |
var documentHeight = document.documentElement.offsetHeight; |
05 |
var viewPortHeight = getViewportSize().h; |
06 |
var scrollHeight = window.pageYOffset || |
07 |
document.documentElement.scrollTop || |
08 |
document.body.scrollTop || 0; |
10 |
return documentHeight - viewPortHeight - scrollHeight < 20; |
判断有了,我们就可以开启一个定时器,900毫秒监测一次,如果isScrollToPageBottom()返回true则调用ajax请求数据,如果返回false则通过900毫秒之后再监测。
下面是核心代码实现:
004 |
<meta charset= "UTF-8" > |
006 |
<link rel= "stylesheet" href= "assets/css/index.css" /> |
010 |
<ul id= "list" class = "list" > |
013 |
<script src= "//cdn.bootcss.com/jquery/3.1.0/jquery.min.js" ></script> |
014 |
<script src= "js/jquery.mockjax.js" ></script> |
015 |
<script type= "text/javascript" src= "js/dataMock.js" ></script> |
016 |
<script type= "text/javascript" > |
018 |
function getViewportSize(w){ |
023 |
if (w.innerWidth != null) |
024 |
return {w: w.innerWidth, h: w.innerHeight}; |
028 |
if (document.compatMode == "CSS1Compat" ) |
029 |
return {w: d.documentElement.clientWidth, h: d.documentElement.clientHeight}; |
032 |
return {w: d.body.clientWidth, h: d.body.clientHeight}; |
036 |
function isScrollToPageBottom(){ |
038 |
var documentHeight = document.documentElement.offsetHeight; |
039 |
var viewPortHeight = getViewportSize().h; |
040 |
var scrollHeight = window.pageYOffset || |
041 |
document.documentElement.scrollTop || |
042 |
document.body.scrollTop || 0; |
044 |
return documentHeight - viewPortHeight - scrollHeight < 20; |
048 |
function getGoodsTemplate(goods){ |
050 |
"<div class='pic-wrap leftFloat'>" + |
051 |
"<img src='" + goods.pic + "'>" + |
053 |
"<div class='info-wrap leftFloat'>" + |
054 |
"<div class='info-name'><span>" + goods.name + "</span></div>" + |
055 |
"<div class='info-address'><span>" + goods.address + "</span></div>" + |
056 |
"<div class='info-bottom'>" + |
057 |
"<div class='info-price leftFloat'><span>¥" + goods.price + "</span></div>" + |
058 |
"<div class='info-star leftFloat'><span>" + goods.star + "人推荐</span></div>" + |
059 |
"<div class='info-more leftFloat'><span>更多信息</span></div>" + |
066 |
$.ajax( "http://localhost:8800/loadData?sessionId=" + (+ new Date )).done( function (result){ |
069 |
result.data.forEach( function (goods){ |
070 |
html += getGoodsTemplate(goods); |
072 |
$( "#list" ).append(html); |
078 |
function loadDataDynamic(){ |
080 |
if ( $( "#loadingLi" ).length === 0) |
081 |
$( "#list" ).append( "<li id='loadingLi' class='loading'>正在加载...</li>" ); |
083 |
$( "#loadingLi" ).text( "正在加载..." ).removeClass( "space" ); |
085 |
var loadingLi = document.getElementById( "loadingLi" ); |
086 |
loadingLi.scrollIntoView(); |
088 |
var hasData = false, msg = "" ; |
089 |
$.ajax( "http://localhost:8800/loadData?sessionId=" + (+ new Date )).done( function (result){ |
091 |
if (result.data.length > 0){ |
094 |
result.data.forEach( function (goods){ |
095 |
html += getGoodsTemplate(goods); |
097 |
$( "#list" ).append(html); |
102 |
$( "#list" ).append(loadingLi); |
105 |
}).always( function (){ |
106 |
!hasData && setTimeout( function (){ |
107 |
$(document.body).scrollTop(document.body.scrollTop -40); |
109 |
msg && $( "#loadingLi" ).text(msg); |
111 |
setTimeout(watchScroll, 900); |
116 |
function watchScroll(){ |
117 |
if (!isScrollToPageBottom()){ |
118 |
setTimeout( arguments.callee, 900); |
demo中ajax请求我是通过jquery-mockjax模拟的数据。代码如下:
04 |
var i = 0, len = 200, addresses = [ "四川" , "北京" , "上海" , "广州" , "深圳" , "甘肃" , "云南" , "浙江" , "青海" , "贵州" ]; |
09 |
var size = Math.min(i + 50, len), arr = []; |
12 |
name: "苹果" + (i % 10 + 1), |
13 |
pic: "assets/images/iphone" + (i % 10 + 1) + ".jpg" , |
14 |
price: parseInt(Math.random() * 10000), |
15 |
star: parseInt(Math.random() * 1000), |
16 |
address: addresses[i % 10] |
24 |
url: 'http://localhost:8800/loadData*' , |
26 |
response: function (settings){ |
|