webapp应用--模拟电子书翻页效果

前言:

     现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过pc访问的趋势。所以,用web程序做出仿原生效果的移动应用,也变得越来越流行了。这种程序也就是我们常说的单页应用程序,它也有一个英文缩写,叫SPA; 它最大的特点就是可以利用前端技术做出跨平台的移动应用。技术难点在于理解虚拟页面与物理页面之间的变换关系。一个偶然的机会,我由php程序员转为web前端开发,主攻javascript编程,不知不觉,已经快两年了。一直有一种想写一个webapp应用框架的冲动,但是各种原因,终究没有付出实践。于是打算从做一个简单的webapp应用开始,万事开头难,今天就搭一个简单的界面。

   webapp应用--模拟电子书翻页效果

HTML代码:

webapp应用--模拟电子书翻页效果
<!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>
View Code

css:

webapp应用--模拟电子书翻页效果
 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 }
View Code

 以上源码将会在页底提供打包下载,这里贴出中间过程,只是想让大家能明白,我是怎么一步一步把这个程序写出来的。如果有疑问的地方就给我留言好了,我会尽量回复。

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

细心的话,你会发现左上角有一个“乱码”,其实那是因为所有的页面都堆叠在一起,造成页数看不清了。这正是我们接下来要解决的问题之一。

js:

webapp应用--模拟电子书翻页效果
 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 }());
View Code

好了,现在看起来仅管还是很丑,但是至少已经符合我预期的样子了。在这里我把第一页已外的页面全部摆到了屏幕的右边,你看不到它们。这样做的目的是要模拟手机上的翻页效果。接下来,就要实现这个非常令人期待的滑动翻页效果。现在该javascript发挥威力的时候了。这是一个简单的应用,我尽量把所有的js写在core.js中,并采用最普通的函数式编程。

webapp应用--模拟电子书翻页效果
 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 }())
View Code

现在我们的程序可以左右翻页了,不过除了页码发生了变化之外,用户好像感觉不到有翻页的效果。左右翻页按钮的作用与我们期望的效果不一致,所以初始化时,把页面堆在右边其实是不太好的,改为左边会更好一些。嗯,还要继续完善。

 

webapp应用--模拟电子书翻页效果
 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 }())
View Code

现在终于看起来像是在翻页的样子了,不过呢,我们在手机上操作的时候,是可以滑动翻页的,这个效果自然也要支持才行。我们先在pc上用鼠标拖动来模拟这一个过程,等逻辑跑通后,再加入触摸事件即可。

 webapp应用--模拟电子书翻页效果

继续下一步之前,我们先小结一下:

首先在初始化代码时,顺道把所有不可见的页面全部堆叠到左边,放在左边的原因是因为我们习惯右边的按钮作为下一页,所以这样摆放,实现起来最简单,我当然要选择最有利于我编码的方式来摆放啦。其次呢,每一次翻页,其实都要移动两个页面。拿点击下一页按钮来说,首先要把当前页移动到不可见的屏幕右边,然后把上一页移到屏幕中间来。上一页的过程正好与之相反。我们发现,点击翻页和滑动翻页,其实都会调用相同的功能。所以在这里可先抽出公共方法,方便代码复用。

接下来,我们实现鼠标拖动翻页的效果。

webapp应用--模拟电子书翻页效果
 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 }())
View Code

这一步我们已经实现了拖动滑页效果,但是感觉怪怪的,对比一下手机上的滑动翻页效果发现,真机上只要我们滑动一定距离之后,页面就自动翻过去了,而不是要我们从一边一直滑到另一边,这样也太不实际了,而且如果我们只滑了一点距离,那么页面会自动归位,也就是常说的反弹效果。要实现这些也不难,我们继续完善代码。

webapp应用--模拟电子书翻页效果
  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 }())
View Code

 最后发现有一点小问题,滑动之后再点翻页按钮,乱套了。仔细分析之后,找出了问题所在,松手时的移动距离不应该用滑动时的最后距离,所以修复很容易。

webapp应用--模拟电子书翻页效果
  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 }())
View Code

到此,这个简易的移动应用就建好了。发现这其实只是搭好了一个架子,里边还有很多内容可以填。比如,给每页加点背景和文字,让页面看起来更加丰满,给标题栏加点工具图标,让它看起来更像是一个原生的apk程序。当我们双击或长按页面空白区域的时候,自动隐藏或显示翻页按钮,增加对更多浏览器的支持,增加对移动设备的支持........

可以发挥的地方太多太多了,锦上添花的事就只好交给各位了。

一步一步做下来,收获了些什么呢?总结一下:

首先要有一个清晰的思路,先确定要实现什么功能,在脑海里有一个整的印象。把UI先建起来,这一步很容易实现,在此基础上,我们就可以看到,有哪些功能需要js去做,哪些效果需要css去做。先易后难。先整体后局部。在做的过程中,一步一步的完善,扩展,优化。一开始就想着要多完美,多优化,结果只是不断的否定自己的想法。不要怕出错,前面的演示中,我们发现,每一步都有些小错误,但是只要我们的整体思路是符合预期的,修正起来就会很快,这个修错的过程,也是一次学习的机地,总结的多了,以后就可以少出错,少被坑。

效果图:

webapp应用--模拟电子书翻页效果

加点内容,是不是立马显得高大上了呀!

源码打包下载:https://github.com/bjtqti/swipe.git

本文系原创,如果喜欢就砸个赞吧!

你可能感兴趣的:(webapp)