下拉刷新,上拉加载基本模型(基本实现)
时间:2023-04-02 11:09:10
HTML
前言现在网上下拉刷新,上拉加载很多插件,如果要在生产环境使用,那你直接网上找靠谱的就可以了,我做的是不依赖任何插件,一步步写这个插件的流程。学生可以在此基础上进行定制。如果你没有写过插件,你可以学习如何编写插件。整个过程定位为入门级。无法阅读?然后百度插件就可以直接使用了。练了一会儿,就在想怎么写个插件。废话不多说,上面效果图中下拉刷新的原理就是添加一个div,标识加载过程,根据下拉的距离改变div的高度,从而显示下拉加载的文本。放手后,根据下拉的距离,判断是否请求数据构建过程定义一些默认的配置项vardefaults={threshold:100,//滑动停止触发下拉刷新的距离:40,//下拉刷新时屏幕顶部到停止位置的距离dis:20//屏幕底部到触发上拉加载的距离}定义构造函数JrRefresh(el,options){this.options=Object.assign({},defaults,options)//合并参数this.el=typeofel==='string'?document.querySelector(el):el//定义要操作的对象this.progress=null//下拉刷新显示的domthis.loadMore=null//上拉加载显示的domthis.progressHeight=0//下拉刷新dom的高度this.rotate=null//下拉刷新圆的角度this.touchstartY=0//触摸到屏幕的坐标起始Y值this.currentY=0//移动时实时记录的坐标Y值this.isAnimation=false//是否自动回滚this.isRefresh=false//是否刷新数据this.isLoadMore=false//是否加载数据this.hasMore=true//是否有更多数据,下拉加载将使用this.rotateTimer=null//控制下拉刷新循环的时间定时器this.event()this.init()}初始化,添加一些需要用到的dom元素JrRefresh.prototype.init=function(){//增加下拉刷新的显示varrefreshHtml=`
下拉刷新 `vardivm=document.createElement('div')divm.innerHTML=refreshHtmlthis.progress=divm.children[0]这个.el。prepend(this.progress)//增加上拉加载的显示varloadMoreHtml=`
正在加载... `vardiv=document.createElement('div')div.innerHTML=loadMoreHtmlthis.loadMore=div.children[0]this.el.appendChild(this.loadMore)}定义事件,说明这里使用的bind,JrRefresh.prototype.pullDown,JrRefresh.prototype.touchend等函数中的this绑定了JrRefresh的构造函数。如果不使用,pullDown函数由this.el调用,this会指向this.el(假装大家都懂?)这是写插件时常用的绑定this的方法之一JrRefresh.prototype.event=function(){this.el.addEventListener('touchstart',this.handleTouchStart.bind(this))this.el.addEventListener('touchmove',this.pullDown.bind(this))this.el.addEventListener('touchend',this.touchend.bind(this))window.addEventListener('scroll',this.handleScroll.bind(this))}记录手指触摸时的Y值坐标,判断是向上滑动还是向下滑动JrRefresh.prototype.handleTouchStart=function(e){//记录手指触摸屏幕的Y值坐标this.touchstartY=e.changedTouches[0].clientY}当手指开始滑动时,触发pullDown事件,this.currentY用于记录实时的Y值坐标。当this.currentY-this.touchstartY>0时,表示手指正在向下滑动。里面的e.preventDefault()是为了防止微信和ios浏览器下拉时顶部默认的黑色空白,或者触发uc等浏览器自带的下拉刷新。this.moveDown用于控制下拉刷新显示的dom(this.progress)高度JrRefresh.prototype.pullDown=function(e){varscrollTop=document.documentElement.scrollTop||窗口.pageYOffset||document.body.scrollTopthis.currentY=e.targetTouches[0].clientYif(this.currentY-this.touchstartY>=0&&scrollTop<=0){e.preventDefault()if(!this.isAnimation&&!this.isRefresh){this.moveDown(this.currentY-this.touchstartY)}}}moveDown函数用于控制this.progress的高度,rotateProgress函数用于控制圆的旋转角度changeProgressState函数用于控制this.progress的显示内容JrRefresh.prototype.moveDown=function(dis){if(dis
{t++varangle=(this.rotate+t*15)%360rotateDom.style.transform='rotate('+angle+'deg)'rotateDom.style.WebkitTransform='rotate('+angle+'deg)'},16)}}changeProgressState这个函数没什么好说的JrRefresh.prototype.changeProgressState=function(name){this.progress.querySelector('.downwarp-tip').innerHTML=name}至此,滑动效果看起来有点像,下面是手指松开时的逻辑窗口.pageYOffset||document.body.scrollTopif(scrollTop>0||this.isRefresh||this.isAnimation)return//只有1.在屏幕顶部2.完成请求数据3.不在回滚中三者都满足processif((this.currentY-this.touchstartY)>this.options.threshold){this.options.downCallback()//触发参数传入的请求数据this.isRefresh=truethis.moveBack(this.options.stop)//下拉刷新时停止位置到屏幕顶部的距离}else{this.moveBack()}}moveBack函数具体返回对应位置的进度JrRefresh.prototype.moveBack=function(dis){vardis=dis||0;this.isAnimation=true//回滚varcurrentHeight=this.progress.offsetHeightvart=0,//步数b=10,//总步数c=(currentHeight-dis)/b//距离每一步vartimer=setInterval(()=>{t++;this.progress.style.height=currentHeight-c*t+'px'if(t==b){if(dis===0){this.changeProgressState('下拉刷新')this.progressHeight=0}else{this.changeProgressState('refreshing')this.progressHeight=this.options.stopthis.rotateProgress()}this.touchstartY=''this.isAnimation=false//回滚完成clearInterval(timer)}},16)}当请求数据完成后,回滚到原位置,参数为boolean类型,表示是否还有数据JrRefresh.prototype.endSuccess=function(bool){if(this.isRefresh){//如果数据正在刷新this.changeProgressState('刷新成功')if(bool){setTimeout(()=>{//延迟500ms回滚this.moveBack(0)this.isRefresh=falseclearInterval(this.rotateTimer)},500)}else{this.toggleLoadingText(true)}}if(this.isLoadMore){//如果正在加载数据this.isLoadMore=falsethis.loadMore.style.visibility='隐藏'this.toggleLoadingText(bool)}}JrRefresh.prototype.toggleLoadingText=function(hasMore){if(hasMore){this.loadMore.querySelector('.upwarp-tip').innerHTML='Loading...'this.loadMore.querySelector('.upwarp-progress').style.display='inline-block'}else{this.loadMore.style.visibility='visible'this.loadMore.querySelector('.upwarp-tip').innerHTML='Thereisnomoredata'this.loadMore.querySelector('.upwarp-progress').style.display='none'}}至此,下拉刷新逻辑终于完成,上拉加载下面开始。比较麻烦的是获取页面高度,数据来的时候请求页面高度,页面还没有渲染出来,页面高度可能不准确,所以我的解决方法是延迟100ms获取高度,JrRefresh.prototype。handleScroll=function(){vartop=this.loadMore.getBoundingClientRect().top;//获取底部标签和屏幕顶部之间的距离if(top+10//list内容,如:.. 好了,就这些吧。想看源码的朋友可以看这里。后续的改进和更新也会放在github上。如果你有兴趣我的同学starorfork