18910140161

移动端网页tab滑动和上下拉刷新加载

顺晟科技

2021-06-16 10:35:32

436

开发这个插件的初衷是在做一个项目的时候,发现在移动终端上实现tab滑动的插件大多是基于swiper的,swiper的功能太强大了,而我只需要一个很小的tab滑动功能,所以需要引入200 k js,太浪费了。而且swiper不具备下拉刷新的功能,需要进行改造才能用swiper实现下拉刷新。实现功能时有很多bug。如果引入下拉刷新插件,必然会增加几十kb的js。而且这些插件对dom结构有一定的要求,不小心就会有bug。是时候在一个插件中修复bug了。

这次开发的插件只靠手势库touch.js使用原生实现函数。只有6kb大小。兼容性也不错。

其实对touch.js的依赖并不严重,只用了两个手势事件,花点时间就可以自己实现。

我只是大致测试了一下插件。如有bug,请提出。如果有不清楚的地方,也请询问。如果你觉得好,你可以给我一颗星

插件基于百度手势库touch.js修改后的手势库大小小于13k。官方文档链接找不到,引用别人写的:API文档

总结一下开发插件的原理和这次遇到的坑

实施主要分为:

确定容器结构

捕捉滑动事件(使用touch.js获取滑动方向、滑动距离和滑动速度)

实现滑动效果(这里用变换实现滑动,用transtion实现动画)

确定临界点(是否根据不同滑动距离切换页面,是否根据滑动速度切换页面)

公开监听事件(在不同状态下生成回调)

坑:

主要体现在微信和ios浏览器下拉时的弹簧效应:

选项卡幻灯片图1

这是浏览器的默认效果,可以用“e.preventDefault()”取消。然而,这将导致容器不滚动。

因此,e.preventDefault()不能直接取消默认效果。默认事件只能在特定条件下取消。条件是什么?

个条件是当它在容器的顶部时,滑动方向是向下的

第二个条件是容器底部的滑动方向向下

在这里,touch.js可以很容易的得到滑动方向,滚动条的位置也很容易计算。一开始我以为很简单,结果发现touch.js在获取滚动方向上有一定的延迟,导致次捕获的位置是最后一次,所以偶尔需要,有时候根本无法滚动。所以用touch.js获取方向是不可取的。

只能自己触摸屏幕时采集坐标,滑动时对比坐标得到方向。好了,这个bug很容易解决。这些都是微信上运行的结构。后来到了uc,发现uc甚至还有左右滑动的默认效果。

这个只能用老办法解决,加两套条件,左右滑动。根据采集到的初始点,对比滑动过程的坐标,判断是上下滚动还是左右滑动。取消默认效果。

API:

Dom结构:

div id='box '!-主集装箱-

div class='pullDownHtml '!-下拉刷新后的显示内容-

Div class='pullDownshow1 '下拉刷新/div

Div class='pullDownshow2 '刷新/div

/div

div class=' pullUpHtml '!-调出加载的显示内容-

Div class=' pullUpHtmlshow1 '上拉负载/div

Div class=' pullUpHtmlshow2 '加载/div

/div

div class='box '

div class='tab-container '

div class='s-pull '

//第1页内容

/div

/div

div class='tab-container '

div class='s-pull '

//第2页内容

/div

/div

div class='tab-container '

div class='s-pull '

//第3页内容

/div

/div

/div

/div

1.初始化

var swiper=new TabSwiper(ele,options)

//ele:容器

//选项:参数(对象)

2.选项参数

{

速度: 300,//动画速度

Threshold: 100,//上拉和下拉触发的阈值(px)

XTHRESHOLD 3360 0.3,//左右滑动触发器的阈值(0~1)默认为‘0.25’

关闭惯性:假。//是否关闭惯性滑行默认启用

isPullDown: true,//是否开启下拉刷新

isPullUp: true,//是否开启上拉加载

defaultPage: 0,//默认显示的页数

initCb:函数(){},//初始化回调

onEnd:函数(页面){},//切换页数时回调(返回当前页数)

onrelfreshstart :函数(页){},//触发下拉刷新时回调(返回当前页数)

onLoadStart:函数(页面){},//触发上拉加载时回调(返回当前页数)

onTouchmove:函数(第e页){}//正在页面上滑动回调(返回当前页数和滑动信息。可通过滑动的信息得到当前滑动的方向速度滑动的距离,进行功能扩展)

}

3、拉端(cb)方法:

swiper.pullEnd(函数(页){//返回当前页数

console.log(页面)

})

4、更改页面(页面)方法:

swiper.changePage(page)//切换页面页目标页面从0开始

5、现在索引属性:

var nowIndex=swiper.nowIndex //获取当前所在页数(只读)

下面是代码(基于es6)

若要查看es5的版本请移步(查看代码)

;(功能(窗口、文档){

//更改改变

函数changeTransform(元素,左侧,顶部){

ele。风格。transform=` translate($ { left } px,${top}px)`

ele。风格。WebKittransform=` translate($ { left } px,${top}px)`

}

class TabSwiper {

get nowIndex () {

归还这个_现在索引

}

设置nowIndex (val) {

if (val===this ._nowIndex)返回

这个_nowIndex=val

这个。选项。把这个合二为一。选项。onend(val)

}

构造函数(ele,options) {

这个_nowIndex=0

this.ele=ele

this.width=ele.clientWidth //容器宽度

this.height=ele.clientHeight //容器高度

this.totalWidth=0 //总宽度

this.box=ele.querySelector(' .方框)

这个。集装箱=ele。查询selectorall(' .制表符-容器')//容器

this.direction=' '

this.scrollTop=0

this.options=options //配置参数

这个。禁止完整=false//禁止上下拉动操作标记

this.startY=0 //起始y坐标

this.startX=0 //起始x坐标

this.isBottom=false //是否在底部

this.disX=0 //滑动X差值

this.disY=0 //滑动Y差值

这个。PullDownHTML=ele。查询选择器(' .下拉Html ')

这个。pulphtml=ele。查询选择器(' .纸浆)

这个。pulldownlhtmlheight=0//下拉的超文本标记语言高度

这个。纸浆高度=0//上拉的超文本标记语言高度

this.left=0 //向左偏移量

//初始化

this.init()

}

//初始化

init () {

这个。选项。Xthreshold=this。选项。Xthreshold | | 0.25

//设置样式

这个。ele。风格。溢出='隐藏'

这个。ele。风格。位置='相对'

this.box.style.height=' '

这个。盒子。风格。宽度=这个。集装箱。长度* 100 '大众'

this.box.style.float='left '

这个。盒子。风格。transition=' all ' this。选项。速度/1000s

这个。盒子。风格。位置='相对'

this.box.style.zIndex=2

这个。TotalWidth=this。宽度*这个。集装箱。长度;

[].foreach。叫(这个。容器,(ele)={

ele.style.float='left '

ele.style.width='100vw '

ele.style.height=' '

ele.style.overflow='auto '

ele。风格。webkitoverflow滚动=' touch '

ele。addeventlistener(' touch start ',(e)={

这个。starty=e . touch[0 ].clientY //设置起始y坐标

这个。StartX=e . touch[0].clientX //设置起始y坐标

},false)

ele。addeventlistener(' touch move ',(e)={

这个。向上滚动=这个。容器[这个。现在索引].scrollTop

这个。IsBottom=this。容器[这个。现在索引].querySelector(' .s-pull ').客户端高度=这个。向上滚动。高度

//判断滑动方向是否为上下

const DIsy=e . touch[0].客户-这个。开始

const DIsX=e . touchs[0].clientX - this.startX

//设置事件(当为顶部或底部是取消默认事件)

if((disY 0 ele。scroll top==0)| | |(DIsy 0 this。IsBottom)){

e.preventDefault()

}

//若为左右滑动时取消默认事件

if(数学。数学。ABS(disX))e . preventdefault()

},false)

})

//上下拉

if (this.options.isPullDown) {

这个。下拉HTML。风格。位置=''

这个。下拉HTML。风格。宽度=' '

这个。pulldownlhtmlheight=this。pulldownlhtml。客户高度

}

if (this.options.isPullUp) {

这个。纸浆html。风格。位置=''

这个。PullPhotml。风格。宽度=' '

这个。纸浆html。风格。底部=' 0 '

这个。pulphtmlheight=this。纸浆html客户端高度

}

//添加事件

//拖拽

touch.on(this.box,' drag ',(e)={

this.direction=e.direction

this.touchmove(e)

这个。选项。走开。选项。OnTouchmove(这个。现在索引,e) //事件输出

})

//滑动

!这个。选项。近距离接触。(这个。框中,“滑动”,(e)={

this.swipe(e)

})

//手指离开屏幕

touch.on(this.box,' touchend ',(e)={

this.touchend(e)

})

//移动至默认页面

这个。ChangePage(此。选项。默认页面| | 0)

这个。选项。初始化这个。选项。initcb()

}

//拖拽方法

touchmove (e) {

这个。盒子。风格。transition=' none '//取消动画

if((e . direction==' left ' | | e . direction==' right ')!this.disY) {

//左右滑动

this.disX=e.distanceX

变换变换(这个。框,(这个。左这个。disX),这个。disY)

} else if(!这个。disX!这个。禁止全){

//上下滑动

if(e . direction==' down '!this.options.isPullDown)返回

if(e . direction==' up '!this.options.isPullUp)返回

if((this。滚动顶部=0。direction==' down ')|(this。这是底部。方向=='向上'){

//上下拉动容器

这个。DisY=e . distaney

变换变换(这个。框,(这个。左这个。disX),这个。disY)

}

}

}

//手指离开屏幕

touchend (e) {

这个。盒子。风格。transition=' all ' this。选项。速度/1000 ' s '//开启动画

if(!这个。禁止全){

if(数学。ABS(这个。disy)这个。选项。阈值){//上下拉小于阀值自动复原

this.disY=0

变换变换(这个。框,(这个。左这个。disX),这个。disY)

}

//下拉刷新触发

if(this。滚动顶部=0 this。方向=='向下'这个。DisY=这个。选项。阈值){

这个。disy=这个。pulldownlhtmlheight

this.prohibitPull=true

//显示加载中

这个。下拉HTML。风格。可见性='可见'

这个。选项。OnRefreshstart这个。选项。OnRefreshstart(此。现在索引)//输出下拉刷新事件

}

//上拉加载触发

else if(this。这是底部。方向=='向上'数学。ABS(这个。disy)这个。选项。阈值){

这个。disy=-这个。纸浆高度

this.prohibitPull=true

//显示加载中

这个。纸浆html。风格。可见性='可见'

这个。选项。启动这个。选项。onload start(此。现在索引)//输出上拉事件

}

}

//左右滑动

if(数学。ABS(这个。DisX)这个。宽度*这个。选项。Xthreshold){

变换变换(这个。盒子,这个。左边,这个。disY)

this.disX=0

} else {

这个。左=这个。disx/数学。ABS(这个。disx)*这个。宽度

if (this.left 0) this.left=0

if(this。左=-这个。总宽度)这个。左=-(这个。总宽度-这个。宽度)

变换变换(这个。盒子,这个。左边,这个。disY)

}

this.direction='' //重置方向

这个。现在索引=数学。ABS(这个。左)/这个。宽度//计算页数

}

//快速滑动

滑动(e) {

if (e.factor 1!这个。disX!this.disY) {

if(e . direction==' left '){

这个。左边-=这个。宽度

} else if(e . direction==' right '){

this.left=this.width

}

if (this.left 0) this.left=0

if(this。左=-这个。总宽度)这个。左=-(这个。总宽度-这个。宽度)

变换变换(这个。盒子,这个。左边,这个。disY)

}

this.disX=0

这个。现在索引=数学。ABS(这个。左)/这个。宽度//计算页数

}

//关闭上下拉

pullEnd (cb) {

cb cb(this.nowIndex)

changeTransform(this.box,this.left,0)

this.disY=0

this.prohibitPull=false

}

//切换页数

变更页面(页面){

if(this。prohibitfull)返回

this.left=-page * this.width

变换变换(这个。盒子,这个。左边,这个。disY)

this.nowIndex=page

}

}

窗户TabSwiper=TabSwiper

})(窗口、文档)

相关文章
我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航