前言:

现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过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:

 ul , li {
margin:;
padding:;
list-style: none;
}
h3,h4,p {
margin:;
padding:;
}
header {
position: absolute;
width:100%;
top:;
left:;
z-index:;
} header h3 {
text-align: center;
height: 3em;
line-height: 3em;
border-bottom: 1px solid green;
} .container {
position: absolute;
width :320px;
height: 480px;
left:320px;
top:2em;
} .root {
position: absolute;
width :100%;
height: 100%;
top :;
left:;
overflow:hidden;
-webkit-perspective:;
-webkit-user-select: none;
-webkit-transform-style:preserve-3d;
} .page {
position: absolute;
width: 318px;
height: 100%;
overflow: hidden;
border:1px solid green;
} .left {
left :2px;
}
.right {
right:2px;
} .left,.right {
position: absolute;
top:45%;
width:3em;
height: 3em;
line-height: 3em;
text-align: center;
border-radius: 15%;
border:1px dashed blue;
} .left:hover,.right:hover {
background-color: #33ff44;
cursor:pointer;
} footer {
position: absolute;
width: 100%;
bottom:;
} h4 {
height: 3em;
line-height: 3em;
text-align: center;
border-top: 1px solid green;
}

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

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

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

js:

 //初始化
;(function(){
var pages = document.querySelectorAll('li');
var width = 320;
var len = pages.length;
var setpost = function(element){
element.style.transform = 'translate3d('+width+'px, 0, 0)';
} //把除1以外的页堆在右边
while(--len){
setpost(pages[len]);
}
}());

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

 //初始化
;(function(){
var pages = document.querySelectorAll('li');
var width = 320;
var len = pages.length;
var setpost = function(element){
element.style.transform = 'translate3d('+width+'px, 0, 0)';
} //把除1以外的页堆在右边
while(--len){
setpost(pages[len]);
}
}()); //控制逻辑
;(function(){
//这里直接使用了新的api,因为移动应用可以这样任性。
var pages = document.querySelectorAll('li');
//左右翻页按钮
var left = document.querySelector('.left');
var right = document.querySelector('.right');
//取得所有的子页面
var pagesLen = pages.length-1; //标记当前页面
var currIndex = 0; //移动页面
var move = function(index,pos){
var width = 320 * pos;
var page = pages[index];
page.style.transform = 'translate3d('+width+'px, 0, 0)';
} //向左翻页
var toLeft = function(){ if(currIndex!==pagesLen){
move(currIndex,-1);
move(++currIndex,0);
}
} //向右翻页
var toRight = function(){
if(currIndex!==0){
move(currIndex,1);
move(--currIndex,0);
}
} //监听动作
left.onclick = function(){
toLeft();
} right.onclick = function(){
toRight();
} }())

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

 //初始化
;(function(){
var pages = document.querySelectorAll('li');
var width = 320;
var len = pages.length;
var setpost = function(element){
element.style.transform = 'translate3d(-'+width+'px, 0, 0)';
} //把除1以外的页堆在左边
while(--len){
setpost(pages[len]);
}
}()); //控制逻辑
;(function(){
//这里直接使用了新的api,因为移动应用可以这样任性。
var pages = document.querySelectorAll('li');
//左右翻页按钮
var left = document.querySelector('.left');
var right = document.querySelector('.right');
//取得所有的子页面
var pagesLen = pages.length-1; //标记当前页面
var currIndex = 0; //移动页面
var move = function(index,pos){
var width = 320 * pos;
var page = pages[index];
page.style.transform = 'translate3d('+width+'px, 0, 0)';
page.style.transitionDuration = '300ms';
} //上一页
var toLeft = function(){
if(currIndex >0){
move(currIndex,-1);
move(--currIndex,0);
}
} //下一页
var toRight = function(){
if(currIndex < pagesLen){
move(currIndex,1);
move(++currIndex,0);
}
} //监听动作
left.onclick = function(){
toLeft();
} right.onclick = function(){
toRight();
} }())

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

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

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

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

 //初始化
;(function(){
var pages = document.querySelectorAll('li');
var width = 320;
var len = pages.length;
var setpost = function(element){
element.style.transform = 'translate3d(-'+width+'px, 0, 0)';
} //把除1以外的页堆在左边
while(--len){
setpost(pages[len]);
}
}()); //控制逻辑
;(function(){
//这里直接使用了新的api,因为移动应用可以这样任性。
var pages = document.querySelectorAll('li');
//左右翻页按钮
var left = document.querySelector('.left');
var right = document.querySelector('.right');
//取得所有的子页面
var pagesLen = pages.length-1;
//屏宽
var screenWidth = 320; //标记当前页面
var currIndex = 0; //标记是否触发滑动
var isTouch = false;
//记录当前位置
var axis = {
x:0,
y:0
} //移动页面
var move = function(index,width,time){
var page = pages[index];
page.style.transform = 'translate3d('+width+'px, 0, 0)';
page.style.transitionDuration = time+'ms';
} //上一页
var toLeft = function(){
if(currIndex >0){
move(currIndex,-screenWidth,300);
move(--currIndex,0,300);
}
} //下一页
var toRight = function(){
if(currIndex < pagesLen){
move(currIndex,screenWidth,300);
move(++currIndex,0,300);
}
} //监听动作
left.onclick = function(){
toLeft();
} right.onclick = function(){
toRight();
} document.addEventListener('mousedown',function(e){
isTouch = true;
axis.x = e.clientX;
axis.y = e.clientY;
}); document.addEventListener('mousemove',function(e){
if(isTouch){
var distance = e.clientX - axis.x;
if(distance>0){
//next
//此时需要看到实时移动效果,所以时间为0
move(currIndex,distance,0);
//当前页与上一页之间总是相差一个屏宽
move(currIndex+1,distance-screenWidth,0);
}else{
//prev
move(currIndex,distance,0);
move(currIndex-1,screenWidth+distance,0); }
}
}); document.addEventListener('mouseup',function(e){
isTouch = false;
}); }())

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

 //初始化
;(function(){
var pages = document.querySelectorAll('li');
var width = 320;
var len = pages.length;
var setpost = function(element){
element.style.transform = 'translate3d(-'+width+'px, 0, 0)';
} //把除1以外的页堆在左边
while(--len){
setpost(pages[len]);
}
}()); //控制逻辑
;(function(){
//这里直接使用了新的api,因为移动应用可以这样任性。
var pages = document.querySelectorAll('li');
//左右翻页按钮
var left = document.querySelector('.left');
var right = document.querySelector('.right');
//取得所有的子页面
var pagesLen = pages.length-1;
//屏宽
var screenWidth = 320;
//反弹时间
var time = 300;
//滑动距离
var distance=0;
//标记当前页面
var currIndex = 0; //标记是否触发滑动
var isTouch = false;
//记录当前位置
var axis = {
x:0,
y:0
} //移动页面
var move = function(index,width,time){
var page = pages[index];
page.style.transform = 'translate3d('+width+'px, 0, 0)';
page.style.transitionDuration = time+'ms';
} //上一页
var toLeft = function(){
if(currIndex >0){
move(currIndex,-screenWidth,time);
move(--currIndex,0,time);
}
} //下一页
var toRight = function(){
if(currIndex < pagesLen){
move(currIndex,screenWidth,time);
move(++currIndex,0,time);
}
} //监听动作
//prev
left.onclick = function(){
toLeft();
}
//next
right.onclick = function(){
toRight();
} document.addEventListener('mousedown',function(e){
isTouch = true;
axis.x = e.clientX;
axis.y = e.clientY;
}); document.addEventListener('mousemove',function(e){
if(isTouch){
distance = e.clientX - axis.x;
if(distance>0){
//next
if(currIndex<pagesLen){
//此时需要看到实时移动效果,所以时间为0
move(currIndex,distance,0);
//当前页与上一页之间总是相差一个屏宽
move(currIndex+1,distance-screenWidth,0);
}
}else{
if(currIndex>0){
//prev
move(currIndex,distance,0);
move(currIndex-1,screenWidth+distance,0);
}
}
}
}); document.addEventListener('mouseup',function(e){
isTouch = false;
//反弹条件
var band = Math.ceil(screenWidth * 0.3);
//next
if(distance >0 && currIndex < pagesLen){
if(distance > band){
toRight();
}else{
//滑动距离太小,页面反弹
move(currIndex,0,time);
move(currIndex+1,-screenWidth,time);
}
return;
}
//prev
if(distance < 0 && currIndex > 0){
if(-distance > band){
toLeft();
}else{
//反弹
move(currIndex,0,time);
move(currIndex-1,screenWidth,time);
}
}
}); }())

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

 //初始化
;(function(){
var pages = document.querySelectorAll('li');
var width = 320;
var len = pages.length;
var setpost = function(element){
element.style.transform = 'translate3d(-'+width+'px, 0, 0)';
} //把除1以外的页堆在左边
while(--len){
setpost(pages[len]);
}
}()); //控制逻辑
;(function(){
//获取所有页面
var pages = document.querySelectorAll('li');
//左右翻页按钮
var left = document.querySelector('.left');
var right = document.querySelector('.right');
//取得所有的子页面
var pagesLen = pages.length-1;
//屏宽
var screenWidth = 320;
//反弹时间
var time = 300; //标记当前页面
var currIndex = 0; //标记是否触发滑动
var isTouch = false;
//记录当前位置
var axis = {
x:0,
y:0
} //移动页面
var move = function(index,width,time){
var page = pages[index];
page.style.transform = 'translate3d('+width+'px, 0, 0)';
page.style.transitionDuration = time+'ms';
} //上一页
var toLeft = function(){
if(currIndex >0){
move(currIndex,-screenWidth,time);
move(--currIndex,0,time);
}
} //下一页
var toRight = function(){
if(currIndex < pagesLen){
move(currIndex,screenWidth,time);
move(++currIndex,0,time);
}
} //监听动作
//prev
left.onclick = function(){
toLeft();
}
//next
right.onclick = function(){
toRight();
} document.addEventListener('mousedown',function(e){
isTouch = true;
axis.x = e.clientX;
axis.y = e.clientY;
}); document.addEventListener('mousemove',function(e){
if(isTouch){
//滑动距离
var distance = e.clientX - axis.x;
if(distance>0){
//next
if(currIndex<pagesLen){
//此时需要看到实时移动效果,所以时间为0
move(currIndex,distance,0);
//当前页与上一页之间总是相差一个屏宽
move(currIndex+1,distance-screenWidth,0);
}
}else{
if(currIndex>0){
//prev
move(currIndex,distance,0);
move(currIndex-1,screenWidth+distance,0);
}
}
}
}); document.addEventListener('mouseup',function(e){
//松手时的移动距离
var distance = e.clientX - axis.x;
//反弹条件
var band = Math.ceil(screenWidth * 0.3);
isTouch = false;
//next
if(distance >0 && currIndex < pagesLen){
if(distance > band){
toRight();
}else{
//滑动距离太小,页面反弹
move(currIndex,0,time);
move(currIndex+1,-screenWidth,time);
}
return;
}
//prev
if(distance < 0 && currIndex > 0){
if(-distance > band){
toLeft();
}else{
//反弹
move(currIndex,0,time);
move(currIndex-1,screenWidth,time);
}
}
}); }())

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

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

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

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

效果图:

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

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

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

webapp应用--模拟电子书翻页效果的更多相关文章

  1. javascript移动端 电子书 翻页效果

    1.后端给一长串的纯文本 2.前端根据屏幕的高度,将文本切割为 n 页 3.使用插件 turn.js 将切割好的每页,加上翻书效果 <!DOCTYPE html> <html lan ...

  2. Android电子书翻页效果实现

    这篇文章是在参考了别人的博客基础上,修改了其中一个翻页bug,并且加了详细注释 先看效果 其中使用了贝赛尔曲线原理,关于贝赛尔曲线的知识,推荐大家看下http://blog.csdn.net/hmg2 ...

  3. 6个超炫酷的HTML5电子书翻页动画

    相信大家一定遇到过一些电子书网站,我们可以通过像看书一样翻页来浏览电子书的内容.今天我们要分享的HTML5应用跟电子书翻页有关,我们精选出来的6个电子书翻页动画都非常炫酷,而且都提供源码下载,有需要的 ...

  4. c#翻页效果

    用c#和GDI+实现杂志翻页动画效果时间:2010-01-13 blog.csdn.net 周公 - 说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇 ...

  5. Android 实现书籍翻页效果----完结篇

    By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处 之前由于种种琐事,暂停了这个翻页效果的实现,终于在这周末完成了大部分功能,但是这里只是给出了一个基本的雏形,没有添 ...

  6. Android 实现书籍翻页效果----升级篇

    自从之前发布了<Android 实现书籍翻页效果----完结篇 >之后,收到了很多朋友给我留言,前段时间由于事情较多,博客写得太匆忙很多细节地方没有描述清楚.所以不少人对其中的地方有不少不 ...

  7. Android 滑动效果高级篇(七)—— 华丽翻页效果

    By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处 之前看到像ipad上的ibook的模拟书籍翻页的特效感觉很炫,在android上也有像laputa和ireader ...

  8. HTML5开发的翻页效果实例

    简介2010年F-i.com和Google Chrome团队合力致力于主题为<20 Things I Learned about Browsers and the Web>(www.20t ...

  9. 微信里经常看到的滑动翻页效果,slide

    上个星期我们的产品姐姐让我帮她写个微信里经常看到的滑动翻页效果,今天抽空写了3个小demo(只写了webkit需要chrome模拟手机看 开启touch事件), 故此写个随笔. 1.demo1,整个大 ...

随机推荐

  1. Be Better:遇见更好的自己-2016年记

    其实并不能找到好的词语来形容过去的一年,感觉就如此平淡的过了!没有了毕业的稚气,看事情淡了,少了一丝浮躁,多了一分认真.2016也许就是那句话-多读书,多看报,少吃零食多睡觉,而我更愿意说--Be B ...

  2. PHP以接口方式实现多重继承(完全模拟)--学习笔记

     1.UML类图: 2.PHP代码: <?php /** * Created by PhpStorm. * User: andy * Date: 16-11-23 * Time: 下午7:57 ...

  3. MVC Core 网站开发(Ninesky) 2、栏目

    栏目是网站的常用功能,按照惯例栏目分常规栏目,单页栏目,链接栏目三种类型,这次主要做添加栏目控制器和栏目模型两个内容,控制器这里会用到特性路由,模型放入业务逻辑层中(网站计划分数据访问.业务逻辑和We ...

  4. 理解nodejs模块的scope

    描述 原文档地址:https://docs.npmjs.com/misc/scope 所有npm模块都有name,有的模块的name还有scope.scope的命名规则和name差不多,同样不能有ur ...

  5. MAC Osx PHP安装指导

    php.ini的位置 Mac OS X中没有默认的php.ini文件,但是有对应的模版文件php.ini.default,位于/private/etc/php.ini.default 或者说 /etc ...

  6. ASP.NET Core 中文文档目录

    翻译计划 五月中旬 .NET Core RC2 如期发布,我们遂决定翻译 ASP.NET Core 文档.我们在 何镇汐先生. 悲梦先生. 张仁建先生和 雷欧纳德先生的群中发布了翻译计划招募信息,并召 ...

  7. 如何使用swing创建一个BeatBox

    首先,我们需要回顾一些内容(2017-01-04 14:32:14): 1.Swing组件 Swing的组件(component,或者称之为元件),是较widget更为正确的术语,它们就是会放在GUI ...

  8. C++常见笔试面试要点以及常见问题

    1. C++常见笔试面试要点: C++语言相关: (1) 虚函数(多态)的内部实现 (2) 智能指针用过哪些?shared_ptr和unique_ptr用的时候需要注意什么?shared_ptr的实现 ...

  9. 跟着老男孩教育学Python开发【第一篇】:初识Python

    Python简介 Python前世今生 Python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解 ...

  10. Mono 3.2.7发布,JIT和GC进一步改进

    Mono 3.2.7已经发布,带来了很多新特性,如改进的JIT.新的面向LINQ的解释器以及使用了64位原生指令等等. 这是一次主要特性发布,累积了大约5个月的开发工作.看上去大部分改进都是底层的性能 ...