导读:这个JS做的翻页效果很有意思,不是我们常见的点击,而是用鼠标拖动后自动翻页,可以向左或向右拖动,具体运行下下面的代码就能看到效果。
原本是为自己的博客网站设计的,周二产生的灵感,周三周四逃课两天算坐标,周五回家,到傍晚才算写出了第一版,发布之后没想到评价还不错,此后太多人问我这个效果应该怎么修改,才能用到自己的网站上,所以现在发这个帖子详细解释一下这个效果的原理
在此正式将此效果命名为 ThrowPage ,而且我肯定会继续完善这个效果,并发布封装好的代码,方便大家调用,可能一个月后,也可能一年后,In Me God Trust
本文将按结构层、表现层、行为层三层分开的顺序来写:
<html><head><title></title> <style type="text/css">html,body{width:100%;height:100%;border:0px; margin:0px;overflow:hidden;}#menu{width:1000px;height:500px;overflow:hidden; background:lightblue;}.page{position:absolute;width:300px;height:400px; left:350px;top:50px;background:#FFF;border:1px solid #999;}ul{list-style:none; height:320px;margin:20px;padding:0px;background:#EEE;}li{font-size:12px; height:20px;line-height:20px;border-bottom:1px dashed #999;}li span{float:right; }li a{color:#000;text-decoration:none;}li a:hover{text-decoration:underline;} .tip{display:block;height:20px;margin:0px 20px;line-height:20px; text-align:center;font-size:12px;background:#999;}</style></head> <body><script type="text/javascript">function id(obj){ return document.getElementById(obj);}var page;var mx;var md=false;var sh=0; var en=false;window.οnlοad=function(){ page=id("menu").getElementsByTagName("div"); if(page.length>0){ page[0].style.zIndex=2; } for(i=0;i<page.length;i++){ page[i].innerHTML+="<span class=\"tip\">"+(i+1)+"/"+page.length+"页 拖拽翻页</span>"; page[i].id="page"+i; page[i].i=i; page[i].οnmοusedοwn=function(e){ if(!en){ if(!e){e=e||window.event;} ex=e.pageX?e.pageX:e.x; mx=350-ex; this.style.cursor="move"; md=true; if(document.all){ this.setCapture(); }else{ window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP); } } } page[i].οnmοusemοve=function(e){ if(md){ en=true; if(!e){e=e||window.event;} ex=e.pageX?e.pageX:e.x; this.style.left=ex+mx+"px"; if(this.offsetLeft<350){ var cu=(this.i==0)?page.length-1:this.i-1; page[sh].style.zIndex=0; page[cu].style.zIndex=1; this.style.zIndex=2; sh=cu; } if(this.offsetLeft>350){ var cu=(this.i==page.length-1)?0:this.i+1; page[sh].style.zIndex=0; page[cu].style.zIndex=1; this.style.zIndex=2; sh=cu; } } } page[i].οnmοuseup=function(){ this.style.cursor="default"; md=false; if(this.offsetLeft==350){ en=false; } if(document.all){ this.releaseCapture(); }else{ window.releaseEvents(Event.MOUSEMOVE|Event.MOUSEUP); } flyout(this); } }}function flyout(obj){ if(obj.offsetLeft < 350){ if( (obj.offsetLeft - 10) > 50 ){ obj.style.left=obj.offsetLeft - 10 + "px"; window.setTimeout("flyout(id('"+obj.id+"'));",0); }else{ obj.style.left= 50 +"px"; obj.style.zIndex=0; flyin(id(obj.id)); } } if(obj.offsetLeft > 350){ if((obj.offsetLeft + 10) < 650){ obj.style.left=obj.offsetLeft + 10 + "px"; window.setTimeout("flyout(id('"+obj.id+"'));",0); }else{ obj.style.left= 650 + "px"; obj.style.zIndex=0; flyin(id(obj.id)); } }} function flyin(obj){ if(obj.offsetLeft<350){ if((obj.offsetLeft + 10) < 350){ obj.style.left=obj.offsetLeft + 10+"px"; window.setTimeout("flyin(id('"+obj.id+"'));",0); }else{ obj.style.left= 350 +"px"; en=false; } } if(obj.offsetLeft>350){ if((obj.offsetLeft - 10) > 350){ obj.style.left=obj.offsetLeft - 10 +"px"; window.setTimeout("flyin(id('"+obj.id+"'));",0); }else{ obj.style.left=350+"px"; en=false; } }}</script> <div id="menu"><div class="page"><ul> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">伴侣</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">美丽岛</a></li> <li style="background:coral;"><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">舞女</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">手牵手</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">初恋的少年家</a></li> </ul></div><div class="page"><ul> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">啊!停不住的爱人</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">网路</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">倾城之雨</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">往事2000</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">绿色恐怖分子</a></li> </ul></div><div class="page"><ul> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">时光在慢慢消失</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">宁静温泉</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">变天着花</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">阿辉饲了一只狗</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">真的假的</a></li> <li><span>09-11-25</span><a href="http://www.oern.cn" _fcksavedurl="http://www.oern.cn" target="_blank">南台湾仔共</a></li> </ul></div></div></body> </html>
提示:您可以先修改部分代码再运行
结构层
要把一个目录的内容按页展开,该怎么写呢?也许是这样,至少我就是这么写的
<div id="menu"> <div class="page"> <ul> <li><span>09-11-25</span><a>恋曲1980</a></li> <li><span>09-11-25</span><a>恋曲1990</a></li> <li><span>09-11-25</span><a>恋曲2000</a></li> <li><span>09-11-25</span><a>母亲</a></li> </ul> <span class="tip">1/2页 拖拽翻页</span> </div> <div class="page"> <ul> <li><span>09-11-25</span><a>伴侣</a></li> <li><span>09-11-25</span><a>思念</a></li> <li><span>09-11-25</span><a>童年</a></li> <li><span>09-11-25</span><a>牧童</a></li> </ul> <span class="tip">2/2页 拖拽翻页</span> </div> </div> |
<ul> 是每一页的列表,图中的浅灰色色部分
<li> 是列表中的一条,图中的珊瑚色部分
<span class="tip"> 是不应该出现在xhtml 中的,应该由 js 添加,它是每一页下面的索引标识,图中的深灰色部分
<div class="page"> 是目录中的页,图中的白色部分
<div id="menu"> 是包含了所有页的目录,图中的亮蓝色部分。当然,如果页面中除了这个效果外没有其他东西的话,这个标签也可以不写,那么所有 <div class="page"> 的父标签就是 <body>
或许你会说,目录也应该是 <ul>,所以应该这么写
<ul id="menu"> <li class="page"> <ul> <li><span>09-11-25</span><a>恋曲1980</a></li> <li><span>09-11-25</span><a>恋曲1990</a></li> <li><span>09-11-25</span><a>恋曲2000</a></li> <li><span>09-11-25</span><a>母亲</a></li> </ul> <span class="tip">1/2页 拖拽翻页</span> </li> <ul class="page"> <ul> <li><span>09-11-25</span><a>伴侣</a></li> <li><span>09-11-25</span><a>思念</a></li> <li><span>09-11-25</span><a>童年</a></li> <li><span>09-11-25</span><a>牧童</a></li> </ul> <span class="tip">2/2页 拖拽翻页</span> </li> </li> |
这样确实更符合语意,不过问题马上就来了
表现层
怎么给上面的嵌套列表定义 CSS 呢?如果万恶的 IE6 支持子对象选择符 “>”,问题很简单。但为了兼容 IE6 和保证 xhtml 部分的简介,在后面另我抓狂的测试中,最终放弃了嵌套列表的方案(事实上,page 类都是由 js 动态设置的)。
让 ThrowPage 应用到你的网页中,其实全靠为页面定义不同的 CSS 实现的,但有几点一定要注意。
<div id="menu"> 应该设置 (overflow:hidden),否则动画过程中可能出现滚动条,影响效果; 每个 <div class="page"> 必须是绝对定位 (position:absolute;) 如果希望出现 <span class="tip">,要为其预留空间,并且 <ul> 是应该有固定高度的 不要用 IE6 的 AlphaImageLoader 滤镜为 <div class="tip"> 添加 PNG 背景,那会让上面的链接在 IE6 中失效 |
暂时就想到这么多,其实还有一些值得注意的,将在下一节作说明
上面图中的 CSS 是这样定义的:
html,body{ width:100%; height:100%; border:0px; margin:0px; overflow:hidden; } #menu{ width:1000px; height:500px; overflow:hidden; background:lightblue; } .page{ position:absolute; width:300px; height:400px; left:350px; top:50px; background:#FFF; border:1px solid #999; } ul{ list-style:none; height:320px; margin:20px; padding:0px; background:#EEE; } li{ font-size:12px; height:20px; line-height:20px; border-bottom:1px dashed #999; } li span{ float:right; } li a{ color:#000; text-decoration:none; } li a:hover{ text-decoration:underline; } .tip{ display:block; height:20px; margin:0px 20px; line-height:20px; text-align:center; font-size:12px; background:#999; } |
行为层
先简单说一下拖动是怎么实现的
其中,A 是绝对定位的,并且有一个 left 值 a,当鼠标在上面按下(onmousedown)时,记录下 b 值,相减算出 c 值
var c; *.οnmοusedοwn=function(e){ if(!e){e=e||window.event;} ex=e.pageX?e.pageX:e.x; c=ex-*.offsetLeft; } |
鼠标按住并且移动时,A 应该随鼠标横向移动,不断产生 d 值,不断设定 A 的 left 值为 d-c,就实现了横向移动,纵向同理。
*.οnmοusemοve=function(e){ if(!e){e=e||window.event;} ex=e.pageX?e.pageX:e.x; *.style.left=ex-c; } |
转到 ThrowPage,其实效果的前半段就是标准的横向拖动
前面为 <div class="page"> 定义了一个 left 值,如果想居中的话,这个值应为
(<div id="menu">宽-<div class="page">宽)/2 |
沿用上面的例子,用到的几个坐标如下图
BD 为 <div class="page"> 的初始位置
AB 为动画中最左状态位置,DE 为最右位置
当然,OF 可以小于 3 倍 BD,A 将小于 0,E 将大于 F
注:如果你是用
.page{ position:absolute; width:x px; left:50%; margin-left:-(x/2)px; } |
实现居中的,涉及的 m-l 值请自行计算
松开鼠标后,停止移动,开始动画,页面左边线(即图中 B,下简称“左边”)可能有以下几种情况:
左边在 A 及 A 的左边-------页面跳到 AB 位置 左边在 AB 中间-------页面移动到 AB 位置 左边在 B-------不进行动画(变态,拽了半天又放回去) 左边在 BD 中间-------页面移动到 DE 位置 左边在 D 及 D 的右边-------页面跳到 DE 位置
题外话:由此可见,移动的距离并不确定,用 JQ 的 animate 的话,时间一定,速度就不一样了,很挠墙。所以我的方法是:向目标位置移动 10 像素(几像素都可以,自己定,其实这就是移动速度),如果没有到目标位置,再移动 10 像素,可以到或者超过的话,直接跳到目标位置(很像递归,但确切的说不是)
向中间回移也是同样道理,故略
z-index 层叠顺序问题:
当最上面的层被拖拽的时候,他下面的一层会被显示,正如上图所示,被拖拽的层 z-index 值为 2,下面显示的一层 z-index 值为 1,再下面的被覆盖的层 z-index 值统统为 0
被拖拽层移动到坐标中 AB 或 DE 后,降一下 z-index 值,飞回的时候就跑到后面去了,同理,“左拖前翻,右拖后翻”的实现关键,是计算好哪一层的 z-index 值应该是 1
附:原帖一些反馈问题和建议的集中回应
页面内容无法选择和复制的问题
这个问题很麻烦的,来看看其他先烈遇到文本带链接的问题是怎么解决的 Word-------按住Ctrl点击打开链接 Emeditor-------点击直接打开链接,无法选择链接中的部分内容\ 浏览器-------同上 Foxit Reader-------切换到编辑模式选择 加了标准头后效果丢失问题
给代码中所有的位置值加上 "px",其实很简单的道理,检查如果所有代码符合 xhtml 标准,效果就不会丢失了 多浏览器兼容的问题
IE6 应该是最头疼的浏览器了吧,所以我选择了 IE6+FF3 的编写和测试环境,其他已测试的浏览器包括 Opera、Safari 和 Chrome,测试时都是最新版本,如果在 BI 的代码框里无法运行,那么保存到本地一定是可以的 前后台代码的问题
已经尽量简化了 xhtml 部分,效果也是在前台实现的,和后台的联系不大,后台只负责按格式输出本文开始时的那个列表就可以了 内存泄漏问题
最近正在学习闭包,试着把全局变量都写进函数,解决内存泄漏问题,God Bless Me,God Bless CHINA 数据量过大时的卡机问题
再次申明,这个效果最初是我为博客目录设计的,不适合大量数据的罗列
况且,看小说和查字典不是一个心态,小说是一页一页翻看的,字典是对着页码查找的
拖拽 200 多页只为找篇文章,不觉得这样的设计很失败么 小距离拖拽不进行效果的建议
本文看明白了就应该知道怎么改了吧,就在 onmouseup 时的坐标判定那里,不过我没有改的打算,不小心翻过了,再拖回去就可以了
本文写得仓促,如果文中出现任何错误,希望大家多做自我批评,欢迎宝贵建议,谢绝无意义赞美贴(MM除外)