JavaScript如何实现上拉加载,下拉刷新?

news/2025/2/14 6:57:21/

一、前言

        下拉刷新和上拉加载这两种交互方式通常出现在移动端中。本质上等同于PC网页中的分页,只是交互形式不同。开源社区也有很多优秀的解决方案,如iscrollbetter-scrollpulltorefresh.js库等等。这些第三方库使用起来非常便捷。我们通过原生的方式实现一次上拉加载,下拉刷新,有助于对第三方库有更好的理解与使用

二、实现原理

        上拉加载及下拉刷新都依赖于用户交互。最重要的是要理解在什么场景,什么时机下触发交互动作

上拉加载

        首先可以看一张图

        上拉加载的本质是页面触底,或者快要触底时的动作。判断页面触底我们需要先了解一下下面几个属性:

  • scrollTop:滚动视窗的高度距离window顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值

  • clientHeight:它是一个定值,表示屏幕可视区域的高度;

  • scrollHeight:页面不能滚动时是不存在的,body长度超过window时才会出现,所表示body所有元素的长度

综上我们得出一个触底公式:

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("开始加载数据");
}

下拉刷新

        下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作。关于下拉刷新的原生实现,主要分成三步:

  • 监听原生touchstart事件,记录其初始位置的值,e.touches[0].pageY

  • 监听原生touchmove事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0表示向下拉动,并借助CSS3的translateY属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值;

  • 监听原生touchend事件,若此时元素滑动达到最大值,则触发callback,同时将translateY重设为0,元素回到初始位置

举个例子:

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>

监听touchstart事件,记录初始的值

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);

监听touchmove移动事件,记录滑动差值

_element.addEventListener('touchmove', function(e) {// e.touches[0].pageY 当前位置_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);

最后,就是监听touchend离开的事件

_element.addEventListener('touchend', function(e) {_element.style.transition = 'transform 0.5s ease 1s';_element.style.transform = 'translateY(0px)';_refreshText.innerText = '更新中...';// todo...}, false);

从上面可以看到,在下拉到松手的过程中,经历了三个阶段:

  • 当前手势滑动位置与初始位置差值大于零时,提示正在进行下拉刷新操作

  • 下拉到一定值时,显示松手释放后的操作提示

  • 下拉到达设定最大值松手时,执行回调,提示正在进行更新操作

三、案例

在实际开发中,我们更多的是使用第三方库,下面以better-scroll进行举例:

HTML结构

<div id="position-wrapper"><div><p class="refresh">下拉刷新</p><div class="position-list"><!--列表内容--></div><p class="more">查看更多</p></div>
</div>

实例化上拉下拉插件,通过use来注册插件

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);

实例化BetterScroll,并传入相关的参数

let pageNo = 1,pageSize = 10,dataList = [],isMore = true;  
var scroll= new BScroll("#position-wrapper",{scrollY:true,//垂直方向滚动click:true,//默认会阻止浏览器的原生click事件,如果需要点击,这里要设为truepullUpLoad:true,//上拉加载更多pullDownRefresh:{threshold:50,//触发pullingDown事件的位置stop:0//下拉回弹后停留的位置}
});
//监听下拉刷新
scroll.on("pullingDown",pullingDownHandler);
//监测实时滚动
scroll.on("scroll",scrollHandler);
//上拉加载更多
scroll.on("pullingUp",pullingUpHandler);async function pullingDownHandler(){dataList=[];pageNo=1;isMore=true;$(".more").text("查看更多");await getlist();//请求数据scroll.finishPullDown();//每次下拉结束后,需要执行这个操作scroll.refresh();//当滚动区域的dom结构有变化时,需要执行这个操作
}
async function pullingUpHandler(){if(!isMore){$(".more").text("没有更多数据了");scroll.finishPullUp();//每次上拉结束后,需要执行这个操作return;}pageNo++;await this.getlist();//请求数据scroll.finishPullUp();//每次上拉结束后,需要执行这个操作scroll.refresh();//当滚动区域的dom结构有变化时,需要执行这个操作    
}
function scrollHandler(){if(this.y>50) $('.refresh').text("松手开始加载");else $('.refresh').text("下拉刷新");
}
function getlist(){//返回的数据let result=....;dataList=dataList.concat(result);//判断是否已加载完if(result.length<pageSize) isMore=false;//将dataList渲染到html内容中
}    

注意点:

使用better-scroll实现下拉刷新、上拉加载时要注意以下几点:

  • wrapper里必须只有一个子元素

  • 子元素的高度要比wrapper要高

  • 使用的时候,要确定DOM元素是否已经生成,必须要等到DOM渲染完成后,再new BScroll()

  • 滚动区域的DOM元素结构有变化后,需要执行刷新 refresh()

  • 上拉或者下拉,结束后,需要执行finishPullUp()或者finishPullDown(),否则将不会执行下次操作

  • better-scroll,默认会阻止浏览器的原生click事件,如果滚动内容区要添加点击事件,需要在实例化属性里设置click:true

小结

        下拉刷新、上拉加载原理本身都很简单,真正复杂的是封装过程中,要考虑的兼容性、易用性、性能等诸多细节

参考文献

  • https://segmentfault.com/a/1190000014423308

  • https://github.com/ustbhuangyi/better-scroll


http://www.ppmy.cn/news/72658.html

相关文章

Java ArrayList

Java ArrayList 目录 Java ArrayList 添加元素 实例 访问元素 实例 修改元素 实例 删除元素 实例 计算大小 实例 迭代数组列表 实例 实例 其他的引用类型 实例 ArrayList 排序 实例 实例 Java ArrayList 方法 正在上传…重新上传取消 Java 集合框架 Arra…

【Linux】7. 进程概念

在进程的学习之前首先需要理解并掌握冯诺依曼体系结构及操作系统的相关概念 1. 冯诺依曼体系结构 最终我们得到的结论是&#xff1a; 在数据层面上 CPU不与外部设备进行交互&#xff0c;而是直接和内存交互所有的外部设备需要数据载入&#xff0c;只能载入到内存中。数据从内…

Spring中的 DI 原理及源码解析

前言 Spring是一个强大的应用程序开发框架&#xff0c;它为企业应用程序提供了许多好处。其中一个主要特性就是IoC&#xff08;控制反转&#xff09;和DI&#xff08;依赖注入&#xff09;。本文将重点介绍Spring中的DI原理以及相关源码解析。 DI的定义 依赖注入&#xff08;D…

文件系统挂载

文件系统挂载 问题claude解决 问题 1.414066] piix4_smbus 0000:00:07.3: SMBus Host Controller not enabled! /dev/sda3: recovering journal /dev/sda3: clean, 287571/1277952 files, 4720254/5110784 blocks [ 2.553460] systemd[1]: Failed to mount /. host:. [ FAILED…

❤ 用JS 从零开始开发一个 Chrome 提示插件(简单易学 10分钟搞定)

❤ 为自己量身手写一个chrome暖心插件&#xff08;资源文章最后&#xff09; ❤ 最近看到了一个很温馨的提示代码,于是想着为自己的浏览器做一款chrome插件 1、chrome 插件理解&#xff1a; 一个html js css image的一个web应用 不同于普通的web应用&#xff0c; chrome插…

软件最后一步------打包

本文章主要是记将源代码打包成程序 Python 一、安装Pyinstaller (用于打包的库) pip install pyinstaller二、使用参数 参数介绍 选项参数参数解释-hhelp(帮助信息)-vversion(版本号)-c显示命令行窗口-w不显示命令行窗口-F生成结果是一个exe程序&#xff0c;所有依赖项被打…

JQuery原理剖析——自己手写简易版JQuery

知其一后知其二&#xff1b; 目录 为什么需要JQuery jQuery的概念&#xff1a; 在此之前回顾JavaScript对象知识&#xff1a; 自己手写的简易JQuery&#xff1a; 为什么需要JQuery 在我们之前写的JS代码中经常会遇见document.getElementById等等获取元素的对象&#xff0c…

python获取某电商平台口红数据并制作词云

目录标题 前言开发环境:模块使用数据来源分析代码展示获取数据制作词云 尾语 &#x1f49d; 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 开发环境: Python 3.8 Pycharm 模块使用 requests jieba 结巴分词 wordcloud 词云 第三方模块安装&#xff1a; win R 输…