背景:
基于要尝试的移动端项目需要有一个通过上拉下滑手势达成加载不同数据的功能,其涉及到滑动手势和ajax数据加载方面的知识点。故对整个实现过程做一个记录整理。个人JS功底有限,看了诸多例子和对于移动端手势知识点梳理的技术博客才做到了对功能的实现。并且也在这个过程中初步了解到了移动端框架Zepto.js。(:з」∠) 当然,最后还是选择了尽量用原生来实现这一功能。因为这样才能够对整个功能实现原理理解上更充分些,想尽量少依赖于插件。不过到了数据加载上,因为时间成本等原因最后还是用上了JQuery来实现ajax的部分。
功能描述:
如下图所示,黄色圆圈为鼠标,当前可以通过上滑和下滑的手势来切换上一周和下一周的数据信息。而当翻到首页或尾页时,会出现提示页告知。除开用JS控制判断的手势和获取的信息状态来输出不同的页面,就是用AJAX来获取具体的JSON数据。
效果展示:
滑动部分实现:
1.获取手指触碰到屏幕时的坐标 (x,y);
2.在限定单手指触碰的大前提下再获取移动后手指在屏幕的坐标位置(x1,y2);
3.使用if来控制坐标 (x,y)与结束坐标(x1,y2)之间的垂直与水平数值差距,将滑动范围限定起来;
4.符合条件的可加载出相应指定数据。
相关链接:
原生JS实现触摸滑动事件http://dobit.top/Detail/109.html
玩转H5上拉下滑动效https://isux.tencent.com/h5-drop-down-effect-slide.html
开源移动端元素拖拽惯性弹动以及下拉加载两个JShttp://www.zhangxinxu.com/wordpress/2017/01/mobile-phone-drag-drop-inertia-loading/
基本是复制了原生JS实现触摸滑动事件的代码后简化改动部分功能来实现这个滑动动效的。并且关于if方面的控制,需要自己再改善。而其他两个例子有给我启发的地方。而且那两个例子的相关讲解也很详细,是值得记录的。
如果各位看官仔细对比原生JS实现触摸滑动事件链接中的代码,会发现真没啥大的区别,而我写这篇文的目的也只是着重于技术点的记录汇总,以及对代码进行自己的理解分析加深印象。当然,不排除我对于这个效果中一些代码的理解是错误的。希望在以后自己的JS技能更成熟以后,能够再回来修改这个帖子。
现在开始以上图项目为例,分述。
<div class="myweekly">
<!--刷新图标,当有新内容加载时,显示该图标,加载完成后图标隐藏-->
<div id="refreshTop"></div>
<div id="pullup">下拉显示上一周</div>
<form role="form" class="info-box my-weekly-box" id="show">
<!--中间刷新区域-->
</form>
<div id="pulldown">上拉显示下一周</div>
<!--刷新图标,当有新内容加载时,显示该图标,加载完成后图标隐藏-->
<div id="refreshbottom"></div>
</div>
var mytouch = (function() {
//先设置相关变量
var x, y,
doc = document,
imgWidth=doc.getElementById("show").clientWidth,//中间显示区域
pullup = doc.getElementById("pullup"),//顶部区域
pulldown = doc.getElementById("pulldown"),//底部区域
isMoved = true; //布尔值,用作阻断事件多次触发
return{ //返回对象
tStart: function(event) { //设置动态参数来获取最开始时触摸到屏幕的坐标信息
if (isMoved) {
//使用touches接收参数位于当前对象触摸点的集合列表(如x轴、y轴坐标数据信息等)
var touches = event.targetTouches;
//获取当前对象所有触摸点的列表,判断长度即判断是有几个触摸点。即当有一个手指最初触摸屏幕时获取坐标
if (touches.length == 1) {
x = touches[0].pageX;
y = touches[0].pageY;
}
isMoved = false; //设置isMoved的值,之后满足条件才会触发后面的滑动事件
}
},
以上为 步骤1 的实现。上面的函数还是比较复杂的,首先它是一个使用了函数标识记法的自调匿名函数,而它的返回值中还显式返回了一个对象方法。如此,虽说自调匿名函数本身是最适合执行一次性或初始化任务的,但因为返回值赋值给了 mytouch
这个变量,该函数不仅具有自行调用的能力,我们也能像使用一般函数一样调用它。
另外上述 var x,y,doc ……
这样的写法需要注意(:з」∠),声明一个变量的时候漏掉了var,这个变量就会默认成全局变量了。
var mytouch = (
function() {
…
return{
tStart: function(event){
…
},
…
}
})();
以下开始正式进入滑动部分
tMove: function(event) { //手指在屏幕上移动时触发上/下滑事件
if (!isMoved) { //只有手指第一次在屏幕上滑动时,并且满足响应条件,才触发上/下滑事件
var touches = event.targetTouches;
if (touches.length == 1) { //一个手指在屏幕上
var x1 = touches[0].pageX, //移动到的坐标
y1 = touches[0].pageY;
if ((y1 - 80) > y ){ //下滑手势
isMoved = true; //不设置该变量,会导致多个touchmove事件
//下滑刷新加载页面,显示顶部刷新图标
doc.getElementById("refreshTop").style.display = "block";
//隐藏 “下滑显示上一周”的文字提示
doc.getElementById("pullup").style.display = "none";
setTimeout(function() { //开始获取数据
//隐藏顶部刷新图标”
doc.getElementById("refreshTop").style.display = "none";
//显示 “下滑显示上一周”的文字提示
doc.getElementById("pullup").style.display = "block";
//这里的 nw 为周数,在这里也可把它当索引值,通过改变它,改变获取的JSON数据信息。
nw --;
//开始使用JQueryAjax获取后台数据,如果为纯前端,
可直接用 innerHTML属性输出页面内容
$.getJSON("/api/weekly.php?week="+ nw +"&session="+session_id,function(json){
if(nw<1){ //判断翻到第一页之后,不能够继续滑动翻页了。
$("#show").html('<div><div>已经翻到第一页了!</div></div>');
nw = 0;//如果不设置该变量,一直上翻的话,nw会为负数,需要阻止进程。
}
else{
//根据后台接口的返回值判断要输出的内容
if(json.status=="已提交" && json.url!="无"){
$("#show").html("");//避免刷新区域有多余html,先做空白刷新。
$("#show").html(
'<div><label>周数:</label><span id="nw">'+
json.week + '周</span></div>' +
'<div><label>提交时间:</label><time id="time">'+
json.time + '</time></div>' +
'<div><label>本周完成:</label><div>'+
json.finished + '</div></div>' +
'<div><label>所遇到问题:</label><div>'+
json.problem + '</div></div>' +
'<div><label>下周计划:</label><div id="plan">'+
json.plan + '</div></div>' +
'<div><label>作品链接:</label><div>'+
json.url + '</div></div>'
);//输出JSON信息,点出JSON对象对应的属性值。
}
//获得其他返回值时,输出其他内容。
……
else{……}
}
return false;
});
}, 500);
}
该下滑部分注释里已经很详细了。其中刚刚触发下滑事件时,刷新图标的出现/隐藏这里是需要改进的。因为这里设置的是一个计时器,以“加载图标”出现的形式告知用户数据正在加载。但是如果后台数据没有获取成功,计时器的时间到了,那么该图标依旧会隐藏,而页面仍然是空白的。对于这个问题,还没能实际写代码解决,先在这里说一下解决思路,可以做一个判断,即在ajax发消息,没有收到返回值就一直是下拉显示“加载图标”的状态,直到收到success
的信息,就开始隐藏“加载图标”;直接收到error
,页面就仅弹上去不刷新;如果数据一直加载不到则设置“刷新超时”的提示。
if ((y1 + 80) < y ){ //上滑
isMoved = true;
//下滑刷新加载页面,显示顶部刷新图标
doc.getElementById("refreshbottom").style.display = "block";
//隐藏 “下滑显示上一周”的文字提示
doc.getElementById("pulldown").style.display = "none";
setTimeout(function() {
doc.getElementById("refreshbottom").style.display = "none";
doc.getElementById("pulldown").style.display = "block";
nw ++;
$.getJSON("/api/weekly.php?week="+ nw +"&session="+session_id,function(json){
//避免出现其他状态,因为在该项目中请假可以请到未来的周数
if(nw>offsetDays+1 && json.status =="未提交"){
nw=offsetDays+2;//设置nw的值
$("#show").html('<div><div>已经翻到最后一页了!</div></div>');
}
else{……
}, 500);
}
}
}
},
};
})();
document.addEventListener("touchstart", mytouch.tStart, false);
document.addEventListener("touchmove", mytouch.tMove, false);
return false;
addEventListener
的方法是为了给元素添加点击事件,这里的false默认的是事件句柄在冒泡阶段执行。