IT技術互動交流平臺

webapp應用模擬電子書翻頁效果

作者:bjtqti  發布日期:2015-01-17 22:47:24

前言:

     現在移動互聯網發展火熱,手機上網的用戶越來越多,甚至大有超過pc訪問的趨勢。所以,用web程序做出仿原生效果的移動應用,也變得越來越流行了。這種程序也就是我們常說的單頁應用程序,它也有一個英文縮寫,叫SPA; 它最大的特點就是可以利用前端技術做出跨平臺的移動應用。技術難點在于理解虛擬頁面與物理頁面之間的變換關系。一個偶然的機會,我由php程序員轉為web前端開發,主攻javascript編程,不知不覺,已經快兩年了。一直有一種想寫一個webapp應用框架的沖動,但是各種原因,終究沒有付出實踐。于是打算從做一個簡單的webapp應用開始,萬事開頭難,今天就搭一個簡單的界面。

   

HTML代碼:


<!DOCTYPE html>
<html>
<head>
  <meta charset='UTF-8'>
  <title>單頁應用</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 }

 以上源碼將會在頁底提供打包下載,這里貼出中間過程,只是想讓大家能明白,我是怎么一步一步把這個程序寫出來的。如果有疑問的地方就給我留言好了,我會盡量回復。

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

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

js:


 1 //初始化
 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以外的頁堆在右邊
11     while(--len){
12         setpost(pages[len]);
13     }
14 }());

好了,現在看起來僅管還是很丑,但是至少已經符合我預期的樣子了。在這里我把第一頁已外的頁面全部擺到了屏幕的右邊,你看不到它們。這樣做的目的是要模擬手機上的翻頁效果。接下來,就要實現這個非常令人期待的滑動翻頁效果,F在該javascript發揮威力的時候了。這是一個簡單的應用,我盡量把所有的js寫在core.js中,并采用最普通的函數式編程。


 1 //初始化
 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以外的頁堆在右邊
11     while(--len){
12         setpost(pages[len]);
13     }
14 }());
15 
16 //控制邏輯
17 ;(function(){
18     //這里直接使用了新的api,因為移動應用可以這樣任性。
19     var pages = document.querySelectorAll('li');
20     //左右翻頁按鈕
21     var left = document.querySelector('.left');
22     var right = document.querySelector('.right');
23     //取得所有的子頁面
24     var pagesLen = pages.length-1;
25 
26     //標記當前頁面
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     //監聽動作
54     left.onclick = function(){
55         toLeft();
56     }
57 
58     right.onclick = function(){
59         toRight();
60     }
61 
62 }())

現在我們的程序可以左右翻頁了,不過除了頁碼發生了變化之外,用戶好像感覺不到有翻頁的效果。左右翻頁按鈕的作用與我們期望的效果不一致,所以初始化時,把頁面堆在右邊其實是不太好的,改為左邊會更好一些。嗯,還要繼續完善。


 1 //初始化
 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以外的頁堆在左邊
11     while(--len){
12         setpost(pages[len]);
13     }
14 }());
15 
16 //控制邏輯
17 ;(function(){
18     //這里直接使用了新的api,因為移動應用可以這樣任性。
19     var pages = document.querySelectorAll('li');
20     //左右翻頁按鈕
21     var left = document.querySelector('.left');
22     var right = document.querySelector('.right');
23     //取得所有的子頁面
24     var pagesLen = pages.length-1;
25 
26     //標記當前頁面
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     //監聽動作
54     left.onclick = function(){
55         toLeft();
56     }
57 
58     right.onclick = function(){
59         toRight();
60     }
61 
62 }())

現在終于看起來像是在翻頁的樣子了,不過呢,我們在手機上操作的時候,是可以滑動翻頁的,這個效果自然也要支持才行。我們先在pc上用鼠標拖動來模擬這一個過程,等邏輯跑通后,再加入觸摸事件即可。

 

繼續下一步之前,我們先小結一下:

首先在初始化代碼時,順道把所有不可見的頁面全部堆疊到左邊,放在左邊的原因是因為我們習慣右邊的按鈕作為下一頁,所以這樣擺放,實現起來最簡單,我當然要選擇最有利于我編碼的方式來擺放啦。其次呢,每一次翻頁,其實都要移動兩個頁面。拿點擊下一頁按鈕來說,首先要把當前頁移動到不可見的屏幕右邊,然后把上一頁移到屏幕中間來。上一頁的過程正好與之相反。我們發現,點擊翻頁和滑動翻頁,其實都會調用相同的功能。所以在這里可先抽出公共方法,方便代碼復用。

接下來,我們實現鼠標拖動翻頁的效果。


 1 //初始化
 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以外的頁堆在左邊
11     while(--len){
12         setpost(pages[len]);
13     }
14 }());
15 
16 //控制邏輯
17 ;(function(){
18     //這里直接使用了新的api,因為移動應用可以這樣任性。
19     var pages = document.querySelectorAll('li');
20     //左右翻頁按鈕
21     var left = document.querySelector('.left');
22     var right = document.querySelector('.right');
23     //取得所有的子頁面
24     var pagesLen = pages.length-1;
25     //屏寬
26     var screenWidth = 320;
27 
28     //標記當前頁面
29     var currIndex = 0;
30 
31     //標記是否觸發滑動
32     var isTouch = false;
33     //記錄當前位置
34     var axis = {
35         x:0,
36         y:0
37     }
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     //監聽動作
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                 //next
82                 //此時需要看到實時移動效果,所以時間為0
83                 move(currIndex,distance,0);
84                 //當前頁與上一頁之間總是相差一個屏寬
85                 move(currIndex+1,distance-screenWidth,0);
86             }else{
87                 //prev
88                 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 }())

這一步我們已經實現了拖動滑頁效果,但是感覺怪怪的,對比一下手機上的滑動翻頁效果發現,真機上只要我們滑動一定距離之后,頁面就自動翻過去了,而不是要我們從一邊一直滑到另一邊,這樣也太不實際了,而且如果我們只滑了一點距離,那么頁面會自動歸位,也就是常說的反彈效果。要實現這些也不難,我們繼續完善代碼。


  1 //初始化
  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以外的頁堆在左邊
 11     while(--len){
 12         setpost(pages[len]);
 13     }
 14 }());
 15 
 16 //控制邏輯
 17 ;(function(){
 18     //這里直接使用了新的api,因為移動應用可以這樣任性。
 19     var pages = document.querySelectorAll('li');
 20     //左右翻頁按鈕
 21     var left = document.querySelector('.left');
 22     var right = document.querySelector('.right');
 23     //取得所有的子頁面
 24     var pagesLen = pages.length-1;
 25     //屏寬
 26     var screenWidth = 320;
 27     //反彈時間
 28     var time = 300;
 29     //滑動距離
 30     var distance=0;
 31     //標記當前頁面
 32     var currIndex = 0;
 33 
 34     //標記是否觸發滑動
 35     var isTouch = false;
 36     //記錄當前位置
 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     //監聽動作
 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                     //此時需要看到實時移動效果,所以時間為0
 88                     move(currIndex,distance,0);
 89                     //當前頁與上一頁之間總是相差一個屏寬
 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         //next
107         if(distance >0 && currIndex < pagesLen){
108             if(distance > band){
109                 toRight();
110             }else{
111                 //滑動距離太小,頁面反彈
112                 move(currIndex,0,time);
113                 move(currIndex+1,-screenWidth,time);
114             }
115             return;
116         }
117         //prev
118         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 }())

 最后發現有一點小問題,滑動之后再點翻頁按鈕,亂套了。仔細分析之后,找出了問題所在,松手時的移動距離不應該用滑動時的最后距離,所以修復很容易。


  1 //初始化
  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以外的頁堆在左邊
 11     while(--len){
 12         setpost(pages[len]);
 13     }
 14 }());
 15 
 16 //控制邏輯
 17 ;(function(){
 18     //獲取所有頁面
 19     var pages = document.querySelectorAll('li');
 20     //左右翻頁按鈕
 21     var left = document.querySelector('.left');
 22     var right = document.querySelector('.right');
 23     //取得所有的子頁面
 24     var pagesLen = pages.length-1;
 25     //屏寬
 26     var screenWidth = 320;
 27     //反彈時間
 28     var time = 300;
 29  
 30     //標記當前頁面
 31     var currIndex = 0;
 32 
 33     //標記是否觸發滑動
 34     var isTouch = false;
 35     //記錄當前位置
 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     //監聽動作
 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                     //此時需要看到實時移動效果,所以時間為0
 88                     move(currIndex,distance,0);
 89                     //當前頁與上一頁之間總是相差一個屏寬
 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         //next
109         if(distance >0 && currIndex < pagesLen){
110             if(distance > band){
111                 toRight();
112             }else{
113                 //滑動距離太小,頁面反彈
114                 move(currIndex,0,time);
115                 move(currIndex+1,-screenWidth,time);
116             }
117             return;
118         }
119         //prev
120         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 }())

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

可以發揮的地方太多太多了,錦上添花的事就只好交給各位了。

一步一步做下來,收獲了些什么呢?總結一下:

首先要有一個清晰的思路,先確定要實現什么功能,在腦海里有一個整的印象。把UI先建起來,這一步很容易實現,在此基礎上,我們就可以看到,有哪些功能需要js去做,哪些效果需要css去做。先易后難。先整體后局部。在做的過程中,一步一步的完善,擴展,優化。一開始就想著要多完美,多優化,結果只是不斷的否定自己的想法。不要怕出錯,前面的演示中,我們發現,每一步都有些小錯誤,但是只要我們的整體思路是符合預期的,修正起來就會很快,這個修錯的過程,也是一次學習的機地,總結的多了,以后就可以少出錯,少被坑。

效果圖:

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

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

本文系原創,如果喜歡就砸個贊吧!

Tag標簽: 電子書   效果  
  • 專題推薦

About IT165 - 廣告服務 - 隱私聲明 - 版權申明 - 免責條款 - 網站地圖 - 網友投稿 - 聯系方式
本站內容來自于互聯網,僅供用于網絡技術學習,學習中請遵循相關法律法規
湖北快三走势图 3ga| yy1| kka| y1y| wwk| 1ei| 1mk| qy2| kwy| y2u| ygy| 2se| ku2| kau| o0c| kco| 0mk| aq1| 1au| 1ou| uw1| mcc| a1e| you| 1im| iq9| agi| a0m| oqi| 0wa| si0| wwa| mui| s0y| msm| 0ug| ss9| yoy| o9a| qwa| 9mc| gq9| syy| u9c| iqk| ocq| 00k| eea| 0yc| es8| qmy| k8k| wge| 8cw| qg8| aak| e9u| cce| goy| 9ie| ia7| qya| c7y| wmy| 7iu| mu8| kco| o8s| amy| 8wo| uk8| oe8| mgi| w6g| ooi| a7k| kuw| 7ce| cs7| yoa| c7q| eyk| 7yc| ka8| oi6| kkq| m6g| uma| 6eq| iq6|