原本是為自己的博客網站設計的,周二產生的靈感,周三周四逃課兩天算坐標,周五回家,到傍晚才算寫出了第一版,發布之後沒想到評價還不錯,此後太多人問我這個效果應該怎麼修改,才能用到自己的網站上,所以現在發這個帖子詳細解釋一下這個效果的原理
在此正式將此效果命名為 ThrowPage ,而且我肯定會繼續完善這個效果,並發布封裝好的代碼,方便大家調用,可能一個月後,也可能一年後,In Me God Trust
本文將按結構層、表現層、行為層三層分開的順序來寫:
運行代碼框
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]
結構層
要把一個目錄的內容按頁展開,該怎麼寫呢?也許是這樣,至少我就是這麼寫的
<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;
*.onmousedown=function(e){
if(!e){e=e||window.event;}
ex=e.pageX?e.pageX:e.x;
c=ex-*.offsetLeft;
}
鼠標按住並且移動時,A 應該隨鼠標橫向移動,不斷產生 d 值,不斷設定 A 的 left 值為 d-c,就實現了橫向移動,縱向同理。
*.onmousemove=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,下簡稱“左邊”)可能有以下幾種情況:
題外話:由此可見,移動的距離並不確定,用 JQ 的 animate 的話,時間一定,速度就不一樣了,很撓牆。所以我的方法是:向目標位置移動 10 像素(幾像素都可以,自己定,其實這就是移動速度),如果沒有到目標位置,再移動 10 像素,可以到或者超過的話,直接跳到目標位置(很像遞歸,但確切的說不是)
向中間回移也是同樣道理,故略
z-index 層疊順序問題:
當最上面的層被拖拽的時候,他下面的一層會被顯示,正如上圖所示,被拖拽的層 z-index 值為 2,下面顯示的一層 z-index 值為 1,再下面的被覆蓋的層 z-index 值統統為 0
被拖拽層移動到坐標中 AB 或 DE 後,降一下 z-index 值,飛回的時候就跑到後面去了,同理,“左拖前翻,右拖後翻”的實現關鍵,是計算好哪一層的 z-index 值應該是 1
附:原帖一些反饋問題和建議的集中回應
本文寫得倉促,如果文中出現任何錯誤,希望大家多做自我批評,歡迎寶貴建議,謝絕無意義贊美貼(MM除外)