背景:
基于要嘗試的移動(dòng)端項(xiàng)目需要有一個(gè)通過上拉下滑手勢(shì)達(dá)成加載不同數(shù)據(jù)的功能,其涉及到滑動(dòng)手勢(shì)和ajax數(shù)據(jù)加載方面的知識(shí)點(diǎn)。故對(duì)整個(gè)實(shí)現(xiàn)過程做一個(gè)記錄整理。個(gè)人JS功底有限,看了諸多例子和對(duì)于移動(dòng)端手勢(shì)知識(shí)點(diǎn)梳理的技術(shù)博客才做到了對(duì)功能的實(shí)現(xiàn)。并且也在這個(gè)過程中初步了解到了移動(dòng)端框架Zepto.js。(:з」∠) 當(dāng)然,最后還是選擇了盡量用原生來實(shí)現(xiàn)這一功能。因?yàn)檫@樣才能夠?qū)φ麄€(gè)功能實(shí)現(xiàn)原理理解上更充分些,想盡量少依賴于插件。不過到了數(shù)據(jù)加載上,因?yàn)闀r(shí)間成本等原因最后還是用上了JQuery來實(shí)現(xiàn)ajax的部分。
功能描述:
如下圖所示,黃色圓圈為鼠標(biāo),當(dāng)前可以通過上滑和下滑的手勢(shì)來切換上一周和下一周的數(shù)據(jù)信息。而當(dāng)翻到首頁或尾頁時(shí),會(huì)出現(xiàn)提示頁告知。除開用JS控制判斷的手勢(shì)和獲取的信息狀態(tài)來輸出不同的頁面,就是用AJAX來獲取具體的JSON數(shù)據(jù)。
效果展示:

滑動(dòng)部分實(shí)現(xiàn):
1.獲取手指觸碰到屏幕時(shí)的坐標(biāo) (x,y);
2.在限定單手指觸碰的大前提下再獲取移動(dòng)后手指在屏幕的坐標(biāo)位置(x1,y2);
3.使用if來控制坐標(biāo) (x,y)與結(jié)束坐標(biāo)(x1,y2)之間的垂直與水平數(shù)值差距,將滑動(dòng)范圍限定起來;
4.符合條件的可加載出相應(yīng)指定數(shù)據(jù)。
相關(guān)鏈接:
原生JS實(shí)現(xiàn)觸摸滑動(dòng)事件http://dobit.top/Detail/109.html
玩轉(zhuǎn)H5上拉下滑動(dòng)效https://isux.tencent.com/h5-drop-down-effect-slide.html
開源移動(dòng)端元素拖拽慣性彈動(dòng)以及下拉加載兩個(gè)JShttp://www.zhangxinxu.com/wordpress/2017/01/mobile-phone-drag-drop-inertia-loading/
基本是復(fù)制了原生JS實(shí)現(xiàn)觸摸滑動(dòng)事件的代碼后簡(jiǎn)化改動(dòng)部分功能來實(shí)現(xiàn)這個(gè)滑動(dòng)動(dòng)效的。并且關(guān)于if方面的控制,需要自己再改善。而其他兩個(gè)例子有給我啟發(fā)的地方。而且那兩個(gè)例子的相關(guān)講解也很詳細(xì),是值得記錄的。
如果各位看官仔細(xì)對(duì)比原生JS實(shí)現(xiàn)觸摸滑動(dòng)事件鏈接中的代碼,會(huì)發(fā)現(xiàn)真沒啥大的區(qū)別,而我寫這篇文的目的也只是著重于技術(shù)點(diǎn)的記錄匯總,以及對(duì)代碼進(jìn)行自己的理解分析加深印象。當(dāng)然,不排除我對(duì)于這個(gè)效果中一些代碼的理解是錯(cuò)誤的。希望在以后自己的JS技能更成熟以后,能夠再回來修改這個(gè)帖子。
現(xiàn)在開始以上圖項(xiàng)目為例,分述。
<div class="myweekly">
<!--刷新圖標(biāo),當(dāng)有新內(nèi)容加載時(shí),顯示該圖標(biāo),加載完成后圖標(biāo)隱藏-->
<div id="refreshTop"></div>
<div id="pullup">下拉顯示上一周</div>
<form role="form" class="info-box my-weekly-box" id="show">
<!--中間刷新區(qū)域-->
</form>
<div id="pulldown">上拉顯示下一周</div>
<!--刷新圖標(biāo),當(dāng)有新內(nèi)容加載時(shí),顯示該圖標(biāo),加載完成后圖標(biāo)隱藏-->
<div id="refreshbottom"></div>
</div>
var mytouch = (function() {
//先設(shè)置相關(guān)變量
var x, y,
doc = document,
imgWidth=doc.getElementById("show").clientWidth,//中間顯示區(qū)域
pullup = doc.getElementById("pullup"),//頂部區(qū)域
pulldown = doc.getElementById("pulldown"),//底部區(qū)域
isMoved = true; //布爾值,用作阻斷事件多次觸發(fā)
return{ //返回對(duì)象
tStart: function(event) { //設(shè)置動(dòng)態(tài)參數(shù)來獲取最開始時(shí)觸摸到屏幕的坐標(biāo)信息
if (isMoved) {
//使用touches接收參數(shù)位于當(dāng)前對(duì)象觸摸點(diǎn)的集合列表(如x軸、y軸坐標(biāo)數(shù)據(jù)信息等)
var touches = event.targetTouches;
//獲取當(dāng)前對(duì)象所有觸摸點(diǎn)的列表,判斷長(zhǎng)度即判斷是有幾個(gè)觸摸點(diǎn)。即當(dāng)有一個(gè)手指最初觸摸屏幕時(shí)獲取坐標(biāo)
if (touches.length == 1) {
x = touches[0].pageX;
y = touches[0].pageY;
}
isMoved = false; //設(shè)置isMoved的值,之后滿足條件才會(huì)觸發(fā)后面的滑動(dòng)事件
}
},
以上為 步驟1 的實(shí)現(xiàn)。上面的函數(shù)還是比較復(fù)雜的,首先它是一個(gè)使用了函數(shù)標(biāo)識(shí)記法的自調(diào)匿名函數(shù),而它的返回值中還顯式返回了一個(gè)對(duì)象方法。如此,雖說自調(diào)匿名函數(shù)本身是最適合執(zhí)行一次性或初始化任務(wù)的,但因?yàn)榉祷刂蒂x值給了 mytouch 這個(gè)變量,該函數(shù)不僅具有自行調(diào)用的能力,我們也能像使用一般函數(shù)一樣調(diào)用它。
另外上述 var x,y,doc …… 這樣的寫法需要注意(:з」∠),聲明一個(gè)變量的時(shí)候漏掉了var,這個(gè)變量就會(huì)默認(rèn)成全局變量了。
var mytouch = (
function() {
…
return{
tStart: function(event){
…
},
…
}
})();
以下開始正式進(jìn)入滑動(dòng)部分
tMove: function(event) { //手指在屏幕上移動(dòng)時(shí)觸發(fā)上/下滑事件
if (!isMoved) { //只有手指第一次在屏幕上滑動(dòng)時(shí),并且滿足響應(yīng)條件,才觸發(fā)上/下滑事件
var touches = event.targetTouches;
if (touches.length == 1) { //一個(gè)手指在屏幕上
var x1 = touches[0].pageX, //移動(dòng)到的坐標(biāo)
y1 = touches[0].pageY;
if ((y1 - 80) > y ){ //下滑手勢(shì)
isMoved = true; //不設(shè)置該變量,會(huì)導(dǎo)致多個(gè)touchmove事件
//下滑刷新加載頁面,顯示頂部刷新圖標(biāo)
doc.getElementById("refreshTop").style.display = "block";
//隱藏 “下滑顯示上一周”的文字提示
doc.getElementById("pullup").style.display = "none";
setTimeout(function() { //開始獲取數(shù)據(jù)
//隱藏頂部刷新圖標(biāo)”
doc.getElementById("refreshTop").style.display = "none";
//顯示 “下滑顯示上一周”的文字提示
doc.getElementById("pullup").style.display = "block";
//這里的 nw 為周數(shù),在這里也可把它當(dāng)索引值,通過改變它,改變獲取的JSON數(shù)據(jù)信息。
nw --;
//開始使用JQueryAjax獲取后臺(tái)數(shù)據(jù),如果為純前端,
可直接用 innerHTML屬性輸出頁面內(nèi)容
$.getJSON("/api/weekly.php?week="+ nw +"&session="+session_id,function(json){
if(nw<1){ //判斷翻到第一頁之后,不能夠繼續(xù)滑動(dòng)翻頁了。
$("#show").html('<div><div>已經(jīng)翻到第一頁了!</div></div>');
nw = 0;//如果不設(shè)置該變量,一直上翻的話,nw會(huì)為負(fù)數(shù),需要阻止進(jìn)程。
}
else{
//根據(jù)后臺(tái)接口的返回值判斷要輸出的內(nèi)容
if(json.status=="已提交" && json.url!="無"){
$("#show").html("");//避免刷新區(qū)域有多余html,先做空白刷新。
$("#show").html(
'<div><label>周數(shù):</label><span id="nw">'+
json.week + '周</span></div>' +
'<div><label>提交時(shí)間:</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>下周計(jì)劃:</label><div id="plan">'+
json.plan + '</div></div>' +
'<div><label>作品鏈接:</label><div>'+
json.url + '</div></div>'
);//輸出JSON信息,點(diǎn)出JSON對(duì)象對(duì)應(yīng)的屬性值。
}
//獲得其他返回值時(shí),輸出其他內(nèi)容。
……
else{……}
}
return false;
});
}, 500);
}
該下滑部分注釋里已經(jīng)很詳細(xì)了。其中剛剛觸發(fā)下滑事件時(shí),刷新圖標(biāo)的出現(xiàn)/隱藏這里是需要改進(jìn)的。因?yàn)檫@里設(shè)置的是一個(gè)計(jì)時(shí)器,以“加載圖標(biāo)”出現(xiàn)的形式告知用戶數(shù)據(jù)正在加載。但是如果后臺(tái)數(shù)據(jù)沒有獲取成功,計(jì)時(shí)器的時(shí)間到了,那么該圖標(biāo)依舊會(huì)隱藏,而頁面仍然是空白的。對(duì)于這個(gè)問題,還沒能實(shí)際寫代碼解決,先在這里說一下解決思路,可以做一個(gè)判斷,即在ajax發(fā)消息,沒有收到返回值就一直是下拉顯示“加載圖標(biāo)”的狀態(tài),直到收到success的信息,就開始隱藏“加載圖標(biāo)”;直接收到error,頁面就僅彈上去不刷新;如果數(shù)據(jù)一直加載不到則設(shè)置“刷新超時(shí)”的提示。
if ((y1 + 80) < y ){ //上滑
isMoved = true;
//下滑刷新加載頁面,顯示頂部刷新圖標(biāo)
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){
//避免出現(xiàn)其他狀態(tài),因?yàn)樵谠擁?xiàng)目中請(qǐng)假可以請(qǐng)到未來的周數(shù)
if(nw>offsetDays+1 && json.status =="未提交"){
nw=offsetDays+2;//設(shè)置nw的值
$("#show").html('<div><div>已經(jīng)翻到最后一頁了!</div></div>');
}
else{……
}, 500);
}
}
}
},
};
})();
document.addEventListener("touchstart", mytouch.tStart, false);
document.addEventListener("touchmove", mytouch.tMove, false);
return false;
addEventListener 的方法是為了給元素添加點(diǎn)擊事件,這里的false默認(rèn)的是事件句柄在冒泡階段執(zhí)行。