YSS

Write Less & Do More

说说无限滚动(infinite scrolling)

前言

在移动端开发中我们即使没有做过无限滚动的事,但也应该接触或者看到过很多类似的东西。特别是在App中。

但是在H5页面中,我们发现在实现无限滚动的路上总是有各种各样的问题。

那现在让我们一一破解吧。

详解

实现无限滚动是一个相对来说比较简单的事情。

基本思路就是,注册滚动监听事件,检测一个放到最后的节点是否出现在屏幕可视区,是则加载新数据。

但是,这里面就碰到了一个问题:

当我们点击新加载的数据,打开一个链接到新的页面,这个时候,我们返回之前的页面,发现根本回不到之前的位置,之后通过异步加载的数据都消失了。

当然这个我们是很好理解的,页面重新加载,一切又都恢复如初。但是作为一个产品,它是绝不被接受的,想想这个糟糕的体验。

然后就有了下面的尝试:

iframe

首先我想到的是使用iframe,把链接装载在里面。点击要跳转的链接,js捕获,存储当前位置信息,创建一个iframe,填制当前跳转链接,显示出来。

一切看似很完美,但是手机端一测试各种问题暴露出来了,每一家都可能会有自己的不同实现。这里主要是谈一下iOS和Android的区别:

  1. IOS下使用iframe,iframe是没有滚动属性的,相当于页面全部平铺下来。这就有个问题,position:fixed失效了。
  2. iframe下各种页面宽度被拉大的问题(实际宽度 > 设备真实宽度)。

面对各种问题,各种调,然后心都碎了一地。。。

内嵌

这种其实是iframe版的变种。也就是把iframe的方式直接换成在页面创建一个节点,然后通过ajax请求需要的页面内容,最后填充到节点里。

是的,这种方案能解决上面使用iframe遇到的问题,但是呢,又碰到的其他问题:

  1. 你需要为展示的页面额外书写ajax请求的数据。
  2. 数据显示都还好说,但是牵扯到业务模型复杂的时候,各种大量js调用和逻辑处理,头都打了。因为里面的内容是随时会被替换的,你需要考虑各种情况。

总结一点就是,是可以做到的,但是代价有点高。

前后配合

我们在来回想一下,我们的问题根本在于,无限滚动后,返回的时候返回不到之前的加载位置以及没有了之前的加载数据。

那我们能不能,返回的时候加载出之前加载的所有数据呢?

答案肯定是能的,我们需要做的就是确保我们返回的页面链接能够展示之前加载的所有数据,所以我们需要做的就是更改之前访问页的链接。

可以做到么?当然可以,我们有history.pushState & history.replaceState

具体关于上面两个方法就不讲解了,我们需要知道的就是它可以更改我们当前页面的链接地址。

实现是这样的:

  1. 我们每加载一次,则改变一次url(这里建议使用history.replaceState),重点是标记总共加载了多少次。
  2. 然后当我们返回的时候,调用了被改变的url,后端在接收到这个url的时候,展示出所有应该加载的数据。

关于第二项可以这么理解,比如默认我是输出10项内容,每一次异步加载都是取的10条数据,那么我异步加载了2次,那么这回输出的数据数量就应该是10 + 2 * 10 = 30

自此,问题就彻底解决了。

最后

有时,借助后端的处理也是一种很好的实现。