移动端实现分页

994 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

我说的移动端的列表分页,并不是像 PC 端那样有一个分页按钮供你选择,有上一页下一页。更多的像是懒加载,第一次只加载一部分数据,滚动到底部的时候如果接口还有数据没有加载完成就继续加载,如果已经加载完了,就不需要加载了。

分页需求

  1. 数据接口需要进行分页,后端数据量特别大,每一次请求接口只会给一部分的数据;
  2. 数据接口不需要进行分页,但是给的数据量特别大,渲染慢,用户需要等待很久,但是用户一般只会看前面的数据;

第一种情况是被迫的分页,第二种是为了用户体验。现在的移动端分页不像以前,还有一个分页的页脚,你去点击上下页切换或者页码跳转。现在的分页都是隐藏的,一个产品有没有分页,专业人士才知道。

实现原理

  1. 监听滚动事件 onScroll ,滚动条的总高度 >= 可视区的高度+距离顶部的距离,表示滚动到底部,这个时候可以进行接口的数据请求,或者添加一部分的数据到列表中去;
  2. 利用 IntersectionObserver 目标元素有没有即将进入我们的视口(用户能不能看到它),即将进入我们的视口,表示已经滚动到了底部,这个时候可以进行接口的数据请求,或者添加一部分的数据到列表中去;

两种实现原理只是使用的东西不一样,底层原理是一样的,就是当用户滚动到底部的时候我们进行数据接口的请求。

第一种方式的关键代码

// 滚动加载数据
onScroll(event) {
  const target = event.target
  // 滚动条的总高度
  const scrollHeight = target.scrollHeight
  // 可视区的高度
  const clientHeight = target.clientHeight
  // 距离顶部的距离
  const scrollTop = target.scrollTop
  // 滚动到底部,在安卓机低下有可能有小数,需要取整
  if (Math.ceil(scrollTop + clientHeight) >= scrollHeight) {
    this.getList() // 接口请求或者添加数据到列表中去
  }
},
   // 获取数据 this.isLoading 前端请求加锁,接口数据没有返回前,滑动到底部,不请求接口,避免重复数据,isFirst是否是第一次请求接口
async getList(isFirst) {
  if (this.isLoading || !this.hasMore) return
  this.showToastMask() // 加载中提醒
  this.isLoading = true
  if (!isFirst) {
    this.params.pageNum++
  }

  const res = await this.$api.xxx(this.params)
  this.isLoading = false
  this.total = res.data.count
  this.list = this.params.pageNum === 1 ? res.data || [] : [...this.list, ...res.data]
  this.hasMore = this.list.length < this.total
  this.toast.hide()
}

第二种实现方式的关键代码

getObserver(){
 const observer = new IntersectionObserver(entry=>{
   if(entry[0]&&entry[0].isIntersecting){
     this.getList()
   }
 });
  observer.observe(document.querySelector('.list-loading-status'))
}

第二种更加灵活,它还能做图片的懒加载,没有进入可视区域,图片就用占位符占位,进去可视区域之后再渲染。在满屏都是图片渲染的时候,这是一个很好的方式。

页面加载时候获取页面的滚动高度,根据滚动高度和页面设置高度做一些操作,比如展开收起。