解决html5上拉加载数据时的一系列问题---页面卡顿、数据重复

页面很简单,先上效果图

吐槽

某日,暴雨,南京的某个角落

领导: 排面,来一下,我有一个小想法 。

我:怎么了,海哥,是不是有新功能要做,我等这一天好久了(MMP 就你想法多,听听歌撩撩妹不好吗)。

领导: 最近用户也突破120万了,项目处在稳定的维护期,所以我想新增加一个小功能 。

我: 什么功能你说吧,作为高级工程师,公司的颜值担当,没有什么是我解决不了的。

领导:我想做个一键洗车功能,给用户展示附近的洗车场,然后提供导航。用 h5实现,后期方便更新维护,你来写 h5和 iOS 。

我:(What?那我的王者荣耀怎么办)恩,您真是有远见,站在用户角度考虑。但我们产品和 UI 刚离职,没有原型和效果图,所以这个想法是不是有点不成熟 。

领导:只要有梦想,人人都是设计师 。

我:(ZZ....)

第二天来公司,我就收到了一副惨无人道的效果图,它大概是这个样子


我怎么怎么办,我也很绝望啊。

正文

前面加载数据的基本操作不做过多描述,直接进入正题。

判断上拉条件

此处后台接口除了返回一个头部信息外 + 10条列表数据,此时的参数 pagenum 为1。当上拉到页面底部时,再发一次 ajax 请求,参数 pagenum为2,以此类推。那么,怎么判断页面刚好到了底部。


假设此时是刚加载完数据的初始状态,可以看到还有一部分数据没有加载出来,处在在屏幕外。当此时手指往上滑动,进入下图这个状态。


所以当监听页面的 touchmove事件。 所有内容高度 = 屏幕高度 + 滑动高度时 。发送 ajax 请求,加载下一页数据。

windowH = $(window).height();
scrollH = $(document).scrollTop();
documentH = document.documentElement.scrollTop==0? document.body.scrollHeight : document.documentElement.scrollHeight;  
if (windowH + scrollH >= documentH - 20) {
      console.log("这里页面到达底部");
     //执行 ajax 操作
     $.ajax({
          datatype : "JSON",
          type : "POST",
          url : "jiekou.htm",
          timeout : 15000,
          async:true,
          data : { key:value,pagenum:pagenum},
          error : function (e) {},
          success : function(json) {
               //for 循环加载数据
               pagenum = parseInt(pagenum) + 1;
          }
     });
}  

这里选择的是异步请求,同步请求当用户网络差或者我们服务器速度慢时,会卡死页面,并且需要等到timeout 之后才能进行下一次刷新加载,严重影响用户体验。

问题关键

但是此时出现了一个新的问题,当滑动到底部时,上面的输出语句 console.log("这里页面到达底部") 会调用数十次。因为 touchmove 事件一直响应,只要满足我们的判断条件,就会进入方法内执行输出语句。

因为我们前面选择的异步请求,所以ajax 请求也会执行数十次,就会出现大量的重复数据。解决这个问题有两个办法:

  • 改为同步请求,一次加载未完成不会进行下一次请求。
  • 继续使用异步,新增一个参数进行判断,当前后两次的pagenum不同才进行新的请求。

第一个方法直接放弃吧,不然会被领导搞死。

if (windowH + scrollH >= documentH - 20) {
    if (pagenum != lastpangenum) {
     //当此时的pagenum跟上一次不同时,才调用
     lastpangenum = pagenum;//更新lastpangenum
     //执行 ajax 操作  
    }
} 

这样做得话问题好像已经被解决了。但是当你把 timeout 参数改的非常小,模拟网络差请求超时情况,发现 if (pagenum != lastpangenum) 条件永远不执行。因为没有走 success 方法,pagenum没有+1所以我们需要处理请求失败的情况。在 error 方法里打破 pagenum = lastpangenum 均衡。完整的代码如下:

if (windowH + scrollH >= documentH - 20) {
  if (pagenum != lastpangenum) {
         lastpangenum = pagenum;//更新lastpangenum
         //执行 ajax 操作
         $.ajax({
          datatype : "JSON",
          type : "POST",
          url : "jiekou.htm",
          timeout : 15000,
          async:true,
          data : { key:value,pagenum:pagenum},
          error : function (e) {
                lastpangenum = lastpangenum - 1;
          },
          success : function(json) {
               //for 循环加载数据
               pagenum = parseInt(pagenum) + 1;
          }
     });
 }
}  

小Tips

问题基本上就是这么多,作为一个非专业前端开发,一切还在摸索的过程中。这里放上几个常用的小方法,以备后用。

1,取当前URL 中的参数
function getUrlVars() {
    var vars = {};
    var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&#]*)/gi,
          function(m,key,value) {
          vars[key] = value;
           }
     );
    return vars;
}

//用法(假设 url 为 www.baidu.com?guid=12345&token=kd1247da)
var guid = getUrlVars()["guid"];
2,获取时间戳,时间戳与正常格式转换
var nowtimestamp = new Date().getTime();//得到时间戳
var commentime = getLocalTime(nowtimestamp);//得到普通格式时间

function getLocalTime(ns) {  
        var d = new Date(ns);  
        var dformat = [ d.getFullYear(), d.getMonth() + 1, d.getDate() ].join('-')   
                    + ' ' + [ d.getHours(), d.getMinutes(), d.getSeconds() ].join(':');  
        return dformat;  
}
3,Android平台与iOS平台判断
var u = navigator.userAgent;
var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if(isAndroid ===true){
}else if(isiOS===true){
}
4,iOS返回不响应
<a href="#" onclick="window.history.back();return false;>
//在后面加return false,屏蔽 a 标签的默认操作

持续更新中...........

结语

整个功能做下来持续了一个多星期,也遇到过不少问题,对于 h5的很多底层原理知之甚少,更谈不上优化。最近在看俞甲子那本程序员的自我修养--链接、装载与库 发现自己对于一些底层知识越来越感兴趣,总觉得它像武林里的内功,一通则百通。好吧,扯得有点远了。等等.....领导好像又在叫我了.......

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容