IT技術互動交(jiao)流平台

北京体彩网官网

作(zuo)者︰bjtqti  發布日期︰2020-02-21 20:08:24

前言(yan)︰

     現在移動互聯網(wang)發展火熱,手機上網(wang)的用(yong)戶越來越多(duo),甚至大有超過(guo)pc訪問的na)魘啤K裕 yong)web程序(xu)做出仿原(yuan)生效果(guo)的移動應用(yong),也變得越來越流行了。這種程序(xu)也就是我(wo)們常說的單頁應用(yong)程序(xu),它(ta)也有一個英文縮寫,叫SPA; 它(ta)最大的特(te)點(dian)就是可以利用(yong)前端(duan)si)際踝齔a href="http://www.it165.net/pro/" target="_blank" class="keylink">跨平台的移動應用(yong)。技術難(nan)點(dian)在于理解虛(xu)擬頁面與物理頁面之間的變換關系(xi)。一個偶然的機會,我(wo)由php程序(xu)員轉為(wei)web前端(duan)開發,主攻(gong)javascript編程,不知不覺,已經快兩年了。一直有一種想寫一個webapp應用(yong)mei)蚣艿某宥  dan)是各種原(yuan)因,終究沒hui)懈凍鍪導S謔譴蛩憒幼 桓黽虻?ebapp應用(yong)mei) 跡 蚴驢 紡nan),今天就搭一個簡單的界面。

   

HTML代碼︰


<!DOCTYPE html><html><head> <meta charset='UTF-8'> <title>單頁應用(yong)</title> <link rel='stylesheet' href='css/common.css' type='text/css'/></head><body><div class='container'> <header> <h3>sameple test </h3> </header> <ul class='root'> <li class='page'>1</li> <li class='page'>2</li> <li class='page'>3</li> <li class='page'>4</li> <li class='page'>5</li> <li class='page'>6</li> <li class='page'>7</li> <li class='page'>8</li> <li class='page'>9</li> <li class='page'>10</li> </ul> <div class='left'>prev</div> <div class='right'>next</div> <footer> <h4>(c)2015 by ouyangli</h4> </footer></div></body><script type='text/javascript' src='lib/core.js'></script></html>

css:


 1 ul , li { 2 margin: 0; 3 padding: 0; 4 list-style: none; 5 } 6 h3,h4,p { 7 margin:0; 8 padding: 0; 9 }10 header {11 position: absolute;12 width:100%;13 top:0;14 left: 0;15 z-index: 9;16 }17 18 header h3 {19 text-align: center;20 height: 3em;21 line-height: 3em;22 border-bottom: 1px solid green;23 }24 25 .container {26 position: absolute;27 width :320px;28 height: 480px;29 left:320px;30 top:2em;31 }32 33 .root {34 position: absolute;35 width :100%;36 height: 100%;37 top :0;38 left:0;39 overflow:hidden;40 -webkit-perspective:1000;41 -webkit-user-select: none;42 -webkit-transform-style:preserve-3d;43 }44 45 .page {46 position: absolute;47 width: 318px;48 height: 100%;49 overflow: hidden;50 border:1px solid green;51 }52 53 .left {54 left :2px;55 }56 .right {57 right:2px;58 }59 60 .left,.right {61 position: absolute;62 top:45%;63 width:3em;64 height: 3em;65 line-height: 3em;66 text-align: center;67 border-radius: 15%;68 border:1px dashed blue;69 }70 71 .left:hover,.right:hover {72 background-color: #33ff44;73 cursor:pointer;74 }75 76 footer {77 position: absolute;78 width: 100%;79 bottom: 0;80 }81 82 h4 {83 height: 3em;84 line-height: 3em;85 text-align: center;86 border-top: 1px solid green;87 }

 以上源碼將會在頁底(di)提供打包下載,這里貼出中間過(guo)程,只是想讓(rang)me)蠹夷 靼祝 wo)是怎麼(me)一步一步把這個程序(xu)寫出來的。如果(guo)有疑問的地方就給我(wo)留言(yan)好(hao)了,我(wo)會盡(jin)量回(hui)復。

演示地址︰http://runjs.cn/detail/o4ql6f6a

細心的話(hua),你會發現左上角(jiao)有一個“亂碼”,其實那(na)是因為(wei)所有的頁面都堆(dui)疊(die)在一起,造(zao)成頁數看不清了。這正(zheng)是我(wo)們接下來要解決的問題之一。

js:


 1 //初始化(hua) 2 ;(function(){ 3 var pages = document.querySelectorAll('li'); 4 var width = 320; 5 var len = pages.length; 6 var setpost = function(element){ 7  element.style.transform = 'translate3d('+width+'px, 0, 0)'; 8 } 9 10 //把除1以外(wai)的頁堆(dui)在右邊11 while(--len){12  setpost(pages[len]);13 }14 }());

好(hao)了,現在看起來僅管還是很(hen)丑(chou),但(dan)是至少已經符合我(wo)預期的nan)恿恕T謖飫鏤wo)把第一頁已外(wai)的頁面全部擺到了屏幕的右邊,你看不到它(ta)們。這樣做的na)康氖且 D饈只系(xi)姆 承?guo)。接下來,就要實現這個非常令人(ren)期待的滑動翻頁效果(guo)。現在該(gai)javascript發揮(hui)威力的時候了。這是一個簡單的應用(yong),我(wo)盡(jin)量把所有的js寫在core.js中,並(bing)采用(yong)最普通的函數式編程。


 1 //初始化(hua) 2 ;(function(){ 3 var pages = document.querySelectorAll('li'); 4 var width = 320; 5 var len = pages.length; 6 var setpost = function(element){ 7  element.style.transform = 'translate3d('+width+'px, 0, 0)'; 8 } 9 10 //把除1以外(wai)的頁堆(dui)在右邊11 while(--len){12  setpost(pages[len]);13 }14 }());15 16 //控制(zhi)邏輯(ji)17 ;(function(){18 //這里直接使用(yong)了新的api,因為(wei)移動應用(yong)mei)梢哉庋ren)性。19 var pages = document.querySelectorAll('li');20 //左右翻頁按鈕(niu)21 var left = document.querySelector('.left');22 var right = document.querySelector('.right');23 //取(qu)得所有的子頁面24 var pagesLen = pages.length-1;25 26 //標(biao)記當前頁面27 var currIndex = 0;28 29 //移動頁面30 var move = function(index,pos){31  var width = 320 * pos;32  var page = pages[index];33  page.style.transform = 'translate3d('+width+'px, 0, 0)';34 }35 36 //向左翻頁37 var toLeft = function(){38 39  if(currIndex!==pagesLen){40  move(currIndex,-1);41  move(++currIndex,0);42  } 43 }44 45 //向右翻頁46 var toRight = function(){47  if(currIndex!==0){48  move(currIndex,1);49  move(--currIndex,0);50  }51 }52 53 //監听動作(zuo)54 left.onclick = function(){55  toLeft();56 }57 58 right.onclick = function(){59  toRight();60 }61 62 }())

現在我(wo)們的程序(xu)可以左右翻頁了,不過(guo)除了頁碼發生了變化(hua)之外(wai),用(yong)戶好(hao)像(xiang)感覺不到有翻頁的效果(guo)。左右翻頁按鈕(niu)的作(zuo)用(yong)與我(wo)們期望的效果(guo)不一致(zhi),所以初始化(hua)時,把頁面堆(dui)在右邊其實是不太(tai)好(hao)的,改(gai)為(wei)左邊會更好(hao)一些。嗯,還要繼續完善(shan)。


 1 //初始化(hua) 2 ;(function(){ 3 var pages = document.querySelectorAll('li'); 4 var width = 320; 5 var len = pages.length; 6 var setpost = function(element){ 7  element.style.transform = 'translate3d(-'+width+'px, 0, 0)'; 8 } 9 10 //把除1以外(wai)的頁堆(dui)在左邊11 while(--len){12  setpost(pages[len]);13 }14 }());15 16 //控制(zhi)邏輯(ji)17 ;(function(){18 //這里直接使用(yong)了新的api,因為(wei)移動應用(yong)mei)梢哉庋ren)性。19 var pages = document.querySelectorAll('li');20 //左右翻頁按鈕(niu)21 var left = document.querySelector('.left');22 var right = document.querySelector('.right');23 //取(qu)得所有的子頁面24 var pagesLen = pages.length-1;25 26 //標(biao)記當前頁面27 var currIndex = 0;28 29 //移動頁面30 var move = function(index,pos){31  var width = 320 * pos;32  var page = pages[index];33  page.style.transform = 'translate3d('+width+'px, 0, 0)';34  page.style.transitionDuration = '300ms';35 }36 37 //上一頁38 var toLeft = function(){39  if(currIndex >0){40  move(currIndex,-1);41  move(--currIndex,0);42  } 43 }44 45 //下一頁46 var toRight = function(){47  if(currIndex < pagesLen){48  move(currIndex,1);49  move(++currIndex,0);50  }51 }52 53 //監听動作(zuo)54 left.onclick = function(){55  toLeft();56 }57 58 right.onclick = function(){59  toRight();60 }61 62 }())

現在終于看起來像(xiang)是在翻頁的nan)恿耍 還guo)呢,我(wo)們在手機上xi)僮zuo)的時候,是可以滑動翻頁的,這個效果(guo)自(zi)然也要支持(chi)才行。我(wo)們先在pc上用(yong)鼠(shu)標(biao)拖(tuo)動來模擬這一個過(guo)程,等邏輯(ji)跑通後,再加(jia)入觸摸事件即可。

 

繼續下一步之前,我(wo)們先小結(jie)一下︰

首先在初始化(hua)代碼時,順(shun)道把所有不可見的頁面全部堆(dui)疊(die)到左邊,放在左邊的原(yuan)因是因為(wei)我(wo)們習慣(guan)右邊的按鈕(niu)作(zuo)為(wei)下一頁,所以這樣擺放,實現zhi)鵠醋羆虻? wo)當然要選擇最有xin)諼wo)編碼的方式來擺放啦(la)。其次呢,每(mei)一次翻頁,其實都要移動兩個頁面。拿點(dian)擊下一頁按鈕(niu)來說,首先要把當前頁移動到不可見的屏幕hui)冶擼 緩蟀焉弦灰騁頻(pin)狡聊恢屑淅礎I弦灰車墓guo)程正(zheng)好(hao)與之相反。我(wo)們發現,點(dian)擊翻頁和滑動翻頁,其實都會調用(yong)相同(tong)的功能。所以在這里可先抽出公(gong)共方法,方便代碼復用(yong)。

接下來,我(wo)們實現鼠(shu)標(biao)拖(tuo)動翻頁的效果(guo)。


 1 //初始化(hua) 2 ;(function(){ 3 var pages = document.querySelectorAll('li'); 4 var width = 320; 5 var len = pages.length; 6 var setpost = function(element){ 7  element.style.transform = 'translate3d(-'+width+'px, 0, 0)'; 8 } 9 10 //把除1以外(wai)的頁堆(dui)在左邊11 while(--len){12  setpost(pages[len]);13 }14 }());15 16 //控制(zhi)邏輯(ji)17 ;(function(){18 //這里直接使用(yong)了新的api,因為(wei)移動應用(yong)mei)梢哉庋ren)性。19 var pages = document.querySelectorAll('li');20 //左右翻頁按鈕(niu)21 var left = document.querySelector('.left');22 var right = document.querySelector('.right');23 //取(qu)得所有的子頁面24 var pagesLen = pages.length-1;25 //屏寬26 var screenWidth = 320;27 28 //標(biao)記當前頁面29 var currIndex = 0;30 31 //標(biao)記是否觸發滑動32 var isTouch = false;33 //記錄當前位置(zhi)34 var axis = {35  x:0,36  y:037 }38 39 //移動頁面40 var move = function(index,width,time){41  var page = pages[index];42  page.style.transform = 'translate3d('+width+'px, 0, 0)';43  page.style.transitionDuration = time+'ms';44 }45 46 //上一頁47 var toLeft = function(){48  if(currIndex >0){49  move(currIndex,-screenWidth,300);50  move(--currIndex,0,300);51  } 52 }53 54 //下一頁55 var toRight = function(){56  if(currIndex < pagesLen){57  move(currIndex,screenWidth,300);58  move(++currIndex,0,300);59  }60 }61 62 //監听動作(zuo)63 left.onclick = function(){64  toLeft();65 }66 67 right.onclick = function(){68  toRight();69 }70 71 document.addEventListener('mousedown',function(e){72  isTouch = true;73  axis.x = e.clientX;74  axis.y = e.clientY;75 });76 77 document.addEventListener('mousemove',function(e){78  if(isTouch){79  var distance = e.clientX - axis.x;80  if(distance>0){81   //next82   //此時需(xu)要看到實時移動效果(guo),所以時間為(wei)083   move(currIndex,distance,0);84   //當前頁與上一頁chi) 渥zong)是相差(cha)一個屏寬85   move(currIndex+1,distance-screenWidth,0);86  }else{87   //prev88   move(currIndex,distance,0);89   move(currIndex-1,screenWidth+distance,0);90 91  }92  }93 });94 95 document.addEventListener('mouseup',function(e){96  isTouch = false;97 });98 99 }())

這一步我(wo)們已經實現了拖(tuo)動滑頁效果(guo),但(dan)是感覺怪(guai)怪(guai)的,對比一下手機上xi)幕   承?guo)發現,真機上只要我(wo)們滑動一定距離之後,頁面就自(zi)動翻過(guo)去了,而不是要我(wo)們從一邊一直bei) 攪硪槐擼 庋蔡tai)不實際了,而且如果(guo)我(wo)們只滑了一點(dian)距離,那(na)麼(me)頁面會自(zi)動歸位,也就是常說的反彈效果(guo)。要實現這些也不難(nan),我(wo)們繼續完善(shan)代碼。


 1 //初始化(hua) 2 ;(function(){ 3 var pages = document.querySelectorAll('li'); 4 var width = 320; 5 var len = pages.length; 6 var setpost = function(element){ 7  element.style.transform = 'translate3d(-'+width+'px, 0, 0)'; 8 } 9 10 //把除1以外(wai)的頁堆(dui)在左邊 11 while(--len){ 12  setpost(pages[len]); 13 } 14 }()); 15 16 //控制(zhi)邏輯(ji) 17 ;(function(){ 18 //這里直接使用(yong)了新的api,因為(wei)移動應用(yong)mei)梢哉庋ren)性。 19 var pages = document.querySelectorAll('li'); 20 //左右翻頁按鈕(niu) 21 var left = document.querySelector('.left'); 22 var right = document.querySelector('.right'); 23 //取(qu)得所有的子頁面 24 var pagesLen = pages.length-1; 25 //屏寬 26 var screenWidth = 320; 27 //反彈時間 28 var time = 300; 29 //滑動距離 30 var distance=0; 31 //標(biao)記當前頁面 32 var currIndex = 0; 33 34 //標(biao)記是否觸發滑動 35 var isTouch = false; 36 //記錄當前位置(zhi) 37 var axis = { 38  x:0, 39  y:0 40 } 41 42 //移動頁面 43 var move = function(index,width,time){ 44  var page = pages[index]; 45  page.style.transform = 'translate3d('+width+'px, 0, 0)'; 46  page.style.transitionDuration = time+'ms'; 47 } 48 49 //上一頁 50 var toLeft = function(){ 51  if(currIndex >0){ 52  move(currIndex,-screenWidth,time); 53  move(--currIndex,0,time); 54  } 55 } 56 57 //下一頁 58 var toRight = function(){ 59  if(currIndex < pagesLen){ 60  move(currIndex,screenWidth,time); 61  move(++currIndex,0,time); 62  } 63 } 64 65 //監听動作(zuo) 66 //prev 67 left.onclick = function(){ 68  toLeft(); 69 } 70 //next 71 right.onclick = function(){ 72  toRight(); 73 } 74 75 document.addEventListener('mousedown',function(e){ 76  isTouch = true; 77  axis.x = e.clientX; 78  axis.y = e.clientY; 79 }); 80 81 document.addEventListener('mousemove',function(e){ 82  if(isTouch){ 83  distance = e.clientX - axis.x; 84  if(distance>0){ 85   //next 86   if(currIndex<pagesLen){ 87   //此時需(xu)要看到實時移動效果(guo),所以時間為(wei)0 88   move(currIndex,distance,0); 89   //當前頁與上一頁chi) 渥zong)是相差(cha)一個屏寬 90   move(currIndex+1,distance-screenWidth,0); 91   } 92  }else{ 93   if(currIndex>0){ 94   //prev 95   move(currIndex,distance,0); 96   move(currIndex-1,screenWidth+distance,0); 97   } 98  } 99  }100 });101 102 document.addEventListener('mouseup',function(e){103  isTouch = false;104  //反彈條件105  var band = Math.ceil(screenWidth * 0.3);106  //next107  if(distance >0 && currIndex < pagesLen){108  if(distance > band){109   toRight();110  }else{111   //滑動距離太(tai)小,頁面反彈112   move(currIndex,0,time);113   move(currIndex+1,-screenWidth,time);114  }115  return;116  }117  //prev118  if(distance < 0 && currIndex > 0){119  if(-distance > band){120   toLeft();121  }else{122   //反彈123   move(currIndex,0,time);124   move(currIndex-1,screenWidth,time);125  }126  }127 });128 129 }())

 最後發現有一點(dian)小問題,滑動之後再點(dian)翻頁按鈕(niu),亂套(tao)了。仔細分析之後,找出了問題所在,松手時的移動距離不hui)Ωgai)用(yong)滑動時的最後距離,所以修復很(hen)容易。


 1 //初始化(hua) 2 ;(function(){ 3 var pages = document.querySelectorAll('li'); 4 var width = 320; 5 var len = pages.length; 6 var setpost = function(element){ 7  element.style.transform = 'translate3d(-'+width+'px, 0, 0)'; 8 } 9 10 //把除1以外(wai)的頁堆(dui)在左邊 11 while(--len){ 12  setpost(pages[len]); 13 } 14 }()); 15 16 //控制(zhi)邏輯(ji) 17 ;(function(){ 18 //獲取(qu)所有頁面 19 var pages = document.querySelectorAll('li'); 20 //左右翻頁按鈕(niu) 21 var left = document.querySelector('.left'); 22 var right = document.querySelector('.right'); 23 //取(qu)得所有的子頁面 24 var pagesLen = pages.length-1; 25 //屏寬 26 var screenWidth = 320; 27 //反彈時間 28 var time = 300; 29 30 //標(biao)記當前頁面 31 var currIndex = 0; 32 33 //標(biao)記是否觸發滑動 34 var isTouch = false; 35 //記錄當前位置(zhi) 36 var axis = { 37  x:0, 38  y:0 39 } 40 41 //移動頁面 42 var move = function(index,width,time){ 43  var page = pages[index]; 44  page.style.transform = 'translate3d('+width+'px, 0, 0)'; 45  page.style.transitionDuration = time+'ms'; 46 } 47 48 //上一頁 49 var toLeft = function(){ 50  if(currIndex >0){ 51  move(currIndex,-screenWidth,time); 52  move(--currIndex,0,time); 53  } 54 } 55 56 //下一頁 57 var toRight = function(){ 58  if(currIndex < pagesLen){ 59  move(currIndex,screenWidth,time); 60  move(++currIndex,0,time); 61  } 62 } 63 64 //監听動作(zuo) 65 //prev 66 left.onclick = function(){ 67  toLeft(); 68 } 69 //next 70 right.onclick = function(){ 71  toRight(); 72 } 73 74 document.addEventListener('mousedown',function(e){ 75  isTouch = true; 76  axis.x = e.clientX; 77  axis.y = e.clientY; 78 }); 79 80 document.addEventListener('mousemove',function(e){ 81  if(isTouch){ 82  //滑動距離 83  var distance = e.clientX - axis.x; 84  if(distance>0){ 85   //next 86   if(currIndex<pagesLen){ 87   //此時需(xu)要看到實時移動效果(guo),所以時間為(wei)0 88   move(currIndex,distance,0); 89   //當前頁與上一頁chi) 渥zong)是相差(cha)一個屏寬 90   move(currIndex+1,distance-screenWidth,0); 91   } 92  }else{ 93   if(currIndex>0){ 94   //prev 95   move(currIndex,distance,0); 96   move(currIndex-1,screenWidth+distance,0); 97   } 98  } 99  }100 });101 102 document.addEventListener('mouseup',function(e){103  //松手時的移動距離104  var distance = e.clientX - axis.x;105  //反彈條件106  var band = Math.ceil(screenWidth * 0.3);107  isTouch = false;108  //next109  if(distance >0 && currIndex < pagesLen){110  if(distance > band){111   toRight();112  }else{113   //滑動距離太(tai)小,頁面反彈114   move(currIndex,0,time);115   move(currIndex+1,-screenWidth,time);116  }117  return;118  }119  //prev120  if(distance < 0 && currIndex > 0){121  if(-distance > band){122   toLeft();123  }else{124   //反彈125   move(currIndex,0,time);126   move(currIndex-1,screenWidth,time);127  }128  }129 });130 131 }())

到此,這個簡易的移動應用(yong)就建(jian)好(hao)了。發現這其實只是搭好(hao)了一個架子,里邊還有很(hen)多(duo)內容可以填。比如,給每(mei)頁加(jia)點(dian)背(bei)景和文字,讓(rang)頁面看起來更加(jia)豐滿,給標(biao)題欄(lan)加(jia)點(dian)工(gong)具圖標(biao),讓(rang)它(ta)看起來更像(xiang)是一個原(yuan)生的apk程序(xu)。當我(wo)們雙擊或長按頁面空白區域的時候,自(zi)動隱藏或顯示翻頁按鈕(niu),增加(jia)對更多(duo)瀏覽器的支持(chi),增加(jia)對移動設備的支持(chi)........

可以發揮(hui)的地方太(tai)多(duo)太(tai)多(duo)了,錦上添花的事就只好(hao)交(jiao)給各位了。

一步一步做下來,收(shou)獲了些什麼(me)呢?總(zong)結(jie)一下︰

首先要有一個清晰的思(si)路(lu),先確fan)ㄒ 迪質裁me)功能,在腦海里有一個整(zheng)的印象。把UI先建(jian)起來,這一步很(hen)容易實現,在此基(ji)礎上,我(wo)們就可以看到,有哪(na)些功能需(xu)要js去做,哪(na)些效果(guo)需(xu)要css去做。先易後難(nan)。先整(zheng)體後局部。在做的過(guo)程中,一步一步的完善(shan),擴展,優化(hua)。一開始就tuo)胱zhou)要多(duo)完美,多(duo)優化(hua),結(jie)果(guo)只是不斷(duan)的否定自(zi)己的想法。不要怕(pa)出錯,前面的nan)菔局校 wo)們發現,每(mei)一步都jia)行┬〈砦wu),但(dan)是只要我(wo)們的整(zheng)體思(si)路(lu)是符合預期的,修正(zheng)起來就會很(hen)快,這個修錯的過(guo)程,也是一次學(xue)習的機地,總(zong)結(jie)的多(duo)了,以後就可以少出錯,少被(bei)坑。

效果(guo)圖︰

加(jia)點(dian)內容,是不是立馬顯得高大上了呀!

源碼打包下載︰https://github.com/bjtqti/swipe.git

本文系(xi)原(yuan)創,如果(guo)喜(xi)歡就砸個贊吧!

Tag標(biao)簽︰電子書  效果(guo)  
About IT165 - 廣告服務 - 隱私聲(sheng)明 - 版權申明 - 免責條款 - 網(wang)站地圖 - 網(wang)友投稿 - 浙江风采网官网聯系(xi)方式
本站內容來自(zi)于互聯網(wang),僅供用(yong)于網(wang)絡技術學(xue)習,學(xue)習中請遵循相關法律法規
北京体彩网官网 | 下一页