在手机端浏览网页时,经常使用一个功能,当我们浏览京东或者淘宝时,页面滑动到底部,我们看到数据自动加载到列表。之前并不知道这些功能是怎么实现的,于是自己在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"> |
| 017 | //作为一个对象的w和h属性返回视口的尺寸 |
| 018 | function getViewportSize(w){ |
| 019 | //使用指定的窗口, 如果不带参数则使用当前窗口 |
| 022 | //除了IE8及更早的版本以外,其他浏览器都能用 |
| 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>" + |
| 065 | //初始化的时候默给list加载100条数据 |
| 066 | $.ajax("http://localhost:8800/loadData?sessionId=" + (+ newDate)).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(); |
| 087 | //加载数据,数据加载完成后需要移除加载提示 |
| 088 | var hasData = false, msg = ""; |
| 089 | $.ajax("http://localhost:8800/loadData?sessionId=" + (+ newDate)).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); |
| 115 | //如果滚动条滚动到页面底部,需要加载新的数据,并且显示加载提示 |
| 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){ |