背景:自己在公司开发移动端的时候,发现swiper的触发函数中好像没有能实现下滑刷新,触发自定义事件的功能,在网上搜索了之后也没有很好demo,决定自己写一个插件,以便以后能实现复用,减少以后的开发时间。在开发过程中自己也学习了很多原生js的东西,发现不依赖jquery和zepto其实也蛮好的,减少了依赖程度。最开始写的时候在想是不是能用scrollTop来实现这个功能,后来才发现本就是应该使用css的transform属性的translate来实现的比较好一些。废话说了这么多,进入正题吧。
- 首先先把架子打好,html加css把这个滑动组件的使用场景写好,就有了如下的demo
在pc端开发移动端的h5页面注意的就是px的像素转换啊,mate设置等,这些在代码里面都有了,我这把就不赘述了。
- 接下来就是考虑如何解决在移动端实现按住屏幕手势滑动,屏幕跟着滑动的问题了
其实现在我们pc端发开的时候,就是一个鼠标点击事件的问题,这里就涉及了js的原生事件,touchstart,touchmove,touchend这三个重要的函数了。简单来说,其实就是在按住的时候,记录下鼠标点击(touchstart)时候的pageY,在鼠标移动(touchmove)的是时候一直记录下此刻的pageY的值,并且根据这个时候pageY值与鼠标点击(touchstart)的时候的差值来设定dom的transform,这样就实现了在不在滚动条滚动范围内实现手势滑动,dom内容也随着滚动,贴上代码(其实要考虑一下滚动内容在容器内的正常情况,这个情况可以用内部dom的高度减去外部容器的高度和外部容器的scrollTop来判断)
function touchStart(e){
startY = e.touches[0].pageY;
num=1;
}
function touchMove(e){
if(_parent.scrollTop>0&&_parent.scrollTop<Difference){
//考虑两个边界的移动情况
startY = e.touches[0].pageY;
}else{
moveY = (e.touches[0].pageY - startY)/2;
var opa = -moveY/singleH;
if(Difference>0){
document.getElementById('bottomtab').style.opacity = opa;
document.getElementById('rotate').style.transform = 'rotate('+opa*180+'deg)';
}
_son.style.transform = "translate(0px,"+moveY+"px)";
}
}
我这边还加上了在移动的时候对于底部元素的透明度和图标rotate的设置,优化一下ui
- 下面介绍一下当我们的手离开屏幕,也就是鼠标松开之后的事件。
当我们滑动的时候,滚动条已经达到边界值,无法支持内部dom继续滚动,在touchmove中我们已经定了函数,支持内容随着我们的手势弹性移动,那么松开的时候如何让他返回他原本改在的边界值呢,其实很简单。只要用一个计时器去让他自己返回去就可以了。涉及的内容就是判断之前的tranform的值是什么样的就可以了(我这把因为在底部加了一个不占位置的css为position:absolute的元素所以要多加一个计时器防止有时候的bug出现。这部分多加的内容其实就是为了显示提示刷新的那些内容,为了更好ui~),贴上代码。
function touchEnd(e){
if(_parent.scrollTop>0&&_parent.scrollTop<Difference){
}else{
if(-moveY>(1/2*singleH)&&Difference>0){
refresh();
}
var tick = setInterval(function(){
if(moveY>=0)
moveY = moveY-adjust(num)<0?0:moveY-adjust(num);
else{
moveY = moveY+adjust(num)>0?0:moveY+adjust(num);
}
_son.style.transform = "translate(0px,"+moveY+"px)";
if(moveY==0||moveY==singleH){
clearInterval(tick);
var sub = setInterval(function(){
if(_parent.scrollTop>Difference){
_parent.scrollTop--;
}else{
clearInterval(sub);
}
},clock)
}
},clock)
}
}
其实看完了这些,大家是不是对我这函数里面很多参数感到云里雾里,因为我再上文中没有很好的介绍清楚哈,我补在文末一下。
//保存点击时候的pageY
var startY = 0;
//保存移动时候的pageY
var moveY = 0;
//设置弹性变量,为了让回到初始位置的时候是一个越来越快的速度
var num = 1;
//调整滑动速度,越大越慢
var aJ = 100;
//调整计时器速度,越大越慢
var clock = 5;
//设置容器内外差
var Difference = 0;
//定义父级dom元素
var _parent = [];
//定义内部滚动的实际内容
var _son = [];
//定义内部滚动内容的每一个节点的高度
var singleH = 0;
//dom就是外部容器,clocktime设置滚动速度
function Elastic(dom,clocktime){
clock = clocktime;
_parent = dom;
_son = dom.children[0];
//设置容器内外差
Difference = _son.offsetHeight-dom.offsetHeight;
if(Difference>0){
//超出容器时候,设置尾部节点,作为刷新提示部分
var node=document.createElement("li");
var textnode=document.createTextNode("");
node.setAttribute('id',"bottomtab");
node.innerHTML = "<i id='rotate'></i><span>释放刷新</span>";
node.appendChild(textnode);
dom.children[0].append(node);
Difference = _son.offsetHeight-dom.offsetHeight;
}
//单个子节点的高度
singleH = dom.children[0].children[0].offsetHeight;
_son.addEventListener('touchstart',touchStart,false);
_son.addEventListener('touchmove',touchMove,false);
_son.addEventListener('touchend',touchEnd,false);
}
function adjust(param){
num++;
return (param++/aJ)
}
这些就是外部插件js里面的所有内容了,如果需要另外引用的话,只需要在html页面定义一下引用函数和刷新事件函数就可以了。另外就是自己定义一下css样式就可以了,总体来说,引用的话不是很麻烦。可能其中还存在一些bug,烦请大家指出谢谢~
https://github.com/lisinw51/swiper-tragger