持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
我说的移动端的列表分页,并不是像 PC 端那样有一个分页按钮供你选择,有上一页下一页。更多的像是懒加载,第一次只加载一部分数据,滚动到底部的时候如果接口还有数据没有加载完成就继续加载,如果已经加载完了,就不需要加载了。
分页需求
- 数据接口需要进行分页,后端数据量特别大,每一次请求接口只会给一部分的数据;
- 数据接口不需要进行分页,但是给的数据量特别大,渲染慢,用户需要等待很久,但是用户一般只会看前面的数据;
第一种情况是被迫的分页,第二种是为了用户体验。现在的移动端分页不像以前,还有一个分页的页脚,你去点击上下页切换或者页码跳转。现在的分页都是隐藏的,一个产品有没有分页,专业人士才知道。
实现原理
- 监听滚动事件
onScroll,滚动条的总高度 >= 可视区的高度+距离顶部的距离,表示滚动到底部,这个时候可以进行接口的数据请求,或者添加一部分的数据到列表中去; - 利用
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'))
}
第二种更加灵活,它还能做图片的懒加载,没有进入可视区域,图片就用占位符占位,进去可视区域之后再渲染。在满屏都是图片渲染的时候,这是一个很好的方式。
页面加载时候获取页面的滚动高度,根据滚动高度和页面设置高度做一些操作,比如展开收起。