实现上拉加载和下拉刷新
通过原生 JavaScript 实现移动端上拉加载和下拉刷新功能
问题
如何在移动端实现上拉加载更多和下拉刷新功能?
解答
上拉加载和下拉刷新本质上是移动端的分页交互方式,通过监听用户的滚动和触摸事件来触发数据加载。
上拉加载
上拉加载的核心是判断页面是否触底。需要理解三个关键属性:
scrollTop:滚动条距离顶部的距离,随滚动变化clientHeight:屏幕可视区域高度,固定值scrollHeight:页面内容总高度
触底判断公式:
scrollTop + clientHeight >= scrollHeight
实现代码:
let clientHeight = document.documentElement.clientHeight;
let scrollHeight = document.body.scrollHeight;
let scrollTop = document.documentElement.scrollTop;
let distance = 50; // 距离底部 50px 时触发
if ((scrollTop + clientHeight) >= (scrollHeight - distance)) {
console.log("开始加载数据");
}
下拉刷新
下拉刷新通过监听触摸事件实现,分为三个步骤:
1. 记录初始位置
var _element = document.getElementById('refreshContainer'),
_refreshText = document.querySelector('.refreshText'),
_startPos = 0,
_transitionHeight = 0;
_element.addEventListener('touchstart', function(e) {
_startPos = e.touches[0].pageY;
_element.style.position = 'relative';
_element.style.transition = 'hd18w 0s';
}, false);
2. 计算滑动距离
_element.addEventListener('touchmove', function(e) {
_transitionHeight = e.touches[0].pageY - _startPos;
if (_transitionHeight > 0 && _transitionHeight < 60) {
_refreshText.innerText = '下拉刷新';
_element.style.transform = 'translateY(' + _transitionHeight + 'px)';
if (_transitionHeight > 55) {
_refreshText.innerText = '释放更新';
}
}
}, false);
3. 触发刷新回调
_element.addEventListener('touchend', function(e) {
_element.style.transition = 'hd18w 0.5s ease 1s';
_element.style.transform = 'translateY(0px)';
_refreshText.innerText = '更新中...';
// 执行刷新逻辑
}, false);
使用 better-scroll 库
实际开发中推荐使用成熟的第三方库。以 better-scroll 为例:
HTML 结构
<div id="position-wrapper">
<div>
<p class="refresh">下拉刷新</p>
<div class="position-list">
<!-- 列表内容 -->
</div>
<p class="more">查看更多</p>
</div>
</div>
初始化插件
import BScroll from "@better-scroll/core";
import PullDown from "@better-scroll/pull-down";
import PullUp from '@better-scroll/pull-up';
BScroll.use(PullDown);
BScroll.use(PullUp);
let pageNo = 1, pageSize = 10, dataList = [], isMore = true;
var scroll = new BScroll("#position-wrapper", {
scrollY: true,
click: true,
pullUpLoad: true,
pullDownRefresh: {
threshold: 50,
stop: 0
}
});
// 监听下拉刷新
scroll.on("pullingDown", async function() {
dataList = [];
pageNo = 1;
isMore = true;
await getlist();
scroll.finishPullDown();
scroll.refresh();
});
// 监听上拉加载
scroll.on("pullingUp", async function() {
if (isMore) {
pageNo++;
await getlist();
scroll.finishPullUp();
scroll.refresh();
}
});
关键点
- 上拉加载通过
scrollTop + clientHeight >= scrollHeight判断触底 - 下拉刷新需要监听
touchstart、touchmove、touchend三个事件 - 使用
transform: translateY()实现元素跟随手势滑动 - better-scroll 的 wrapper 内只能有一个子元素,且子元素高度必须大于 wrapper
- 每次操作结束后必须调用
finishPullDown()或finishPullUp(),并执行refresh()更新滚动区域
目录