【前端】原生实现上拉加载和下拉刷新
Dandelion 10/4/2022 JS
# 概述
上拉加载及下拉刷新都依赖于用户交互,关键是要理解在什么场景,什么时机下触发交互动作。
开源解决方案:iscroll
、better-scroll
、pulltorefresh.js
等第三方库。
- 上拉加载
- 下拉刷新
- 示例 HTML 结构
<main> <p class="refreshText"></p> <ul id="refreshContainer"> <li>111</li> <li>222</li> <li>333</li> <li>444</li> <li>555</li> ... </ul> </main>
1
2
3
4
5
6
7
8
9
10
11
# 上拉加载
基本原理:如何判断页面触底?
- scrollTop:滚动视窗的高度距离 window 顶部的距离,它会随着往上滚动而不断增加,初始值是 0,它是一个变化的值。
- clientHeight:一个固定的值,表示屏幕可视区域的高度。
- scrollHeight:页面不能滚动时也是存在的,此时等于 clientHeight。scrollHeight 表示 body 所有元素的总长度(包括 body 自身的 padding)。
公式表示:
scrollTop + clientHeight >= scrollHeight
代码实现:
let clientHeight = document.documentElement.clientHeight; let scrollHeight = document.body.scrollHeight; let scrollTop = document.documentElement.scrollTop; let distance = 50; //距离视窗还用50的时候,开始触发 if (scrollTop + clientHeight >= scrollHeight - distance) { console.log('开始加载数据'); }
1
2
3
4
5
6
7
# 下拉刷新
基本原理:页面本身置于顶部时,用户下拉时需要触发的动作。
Step1:监听原生
touchstart
事件,记录其初始位置的值,即e.touches[0].pageY
。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 = 'transform 0s'; }, false );
1
2
3
4
5
6
7
8
9
10
11
12
13
14Step2:监听原生
touchmove
事件,记录并计算当前滑动的位置值与初始位置值的差值,大于 0 表示向下拉动,并借助 CSS3 的translateY
属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值。_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 );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Step3:监听原生
touchend
事件,若此时元素滑动达到最大值,则触发 callback,同时将translateY
重设为 0,元素回到初始位置。_element.addEventListener( 'touchend', function (e) { _element.style.transition = 'transform 0.5s ease 1s'; _element.style.transform = 'translateY(0px)'; _refreshText.innerText = '更新中...'; // todo... }, false );
1
2
3
4
5
6
7
8
9
10