效果就像優酷綜藝頻道頁面的圖片輪播。
本屌以前作過這個roundabout,參見仿優酷頻道首頁的圖片切換效果,不過用的是相似jquery的庫作的。儘管js代碼不到200行,但仍是顯得有點複雜。因而乎,本屌盤算着可不能夠用更少的代碼完成這個效果。
順便說一下,若是有讀者想造輪子,能夠直接看優酷的js代碼,基本上都沒壓縮,封裝這個效果的代碼在posterTvGrid.js
下面是本屌作出來的效果
http://v.youku.com/v_show/id_XMTM1ODk4NDQyNA==.htmljavascript
點擊左右箭頭,圖片滾動css
點擊下面圖片索引,若是點擊的圖片是當前圖片或與當前圖片相鄰的圖片,則圖片滾動;不然,全部圖片先變小,而後點擊的圖片和與之相鄰的圖片,在相應位置動態變大。html
代碼儘量少,儘量清晰java
<div id='wrap' ms-controller='roundabout'> <div id='roundabout'> <ul> <li ms-repeat-img='img_list' ms-attr-id='img{{$index}}'> <img ms-attr-src="img/{{img}}.jpeg"> </li> </ul> </div> </div>
圖片的位置有2種狀況:jquery
不可見,即不是前面的3張圖片,這裏類名.hide
css3
.hide { width: 530px; height: 100px; opacity: 0; z-index: 0; margin-top: 0; left: -530px; }
可見的3張圖片,按位置具體可分爲.left
,.middle
,.right
git
.middle { width: 640px; height: 270px; opacity: 1; z-index: 2; margin-top: 0; left: 275px; } .left { width: 530px; height: 224px; opacity: 0.4; z-index: 1; margin-top: 23px; left: 0; } .right { width: 530px; height: 224px; opacity: 0.4; z-index: 1; margin-top: 23px; left: 660px; }
每一個類的6個屬性都是和圖片尺寸(640*270)配合好的,使得動畫很天然。固然後面會用到css3 animation,使每張圖片的這6個屬性進行相應的變化。
下面把上面類添加到相應圖片上github
var roundabout=avalon.define({ $id:'roundabout', img_list:[], cur:0,//當前頁 ... });
cur
相對於指針,表示當前中間(可見範圍最大)圖片是圖片列表裏的哪張圖片,因此會有(從左向右看)編程
cur
=>.middle
less
cur+1
=>.right
cur-1
=>.left
其餘
=>.hide
這裏就要把邏輯運算符用到插值表達式裏
<div id='roundabout'> <ul> <li ms-repeat-img='img_list' ms-attr-id='img{{$index}}' ms-class-hide='($index<cur-1&&(cur!=img_list.size()-1||$index!=0))|| ($index>cur+1&&(cur!=0||$index!=img_list.size()-1))' ms-class-left='$index==cur-1||(cur==0&&$index==img_list.size()-1)' ms-class-right='$index==cur+1||(cur==img_list.size()-1&&$index==0)' ms-class-middle='$index==cur' class='animated'> <img ms-attr-src="img/{{img}}.jpeg"> </li> </ul> </div>
解釋下ms-class-middle='$index==cur'
這個很簡單,指針的當前位置,添加.middle
.
ms-class-left='$index==cur-1||(cur==0&&$index==img_list.size()-1)'
後面部分表示,若是指針在第一張圖片那裏,就在最後一張圖片上添加.left
.
ms-class-right='$index==cur+1||(cur==img_list.size()-1&&$index==0)'
和上面相似,後面部分表示,若是指針在最後一張圖片那裏,就在第一張圖片上添加.right
.
ms-class-hide='($index<cur-1&&(cur!=img_list.size()-1||$index!=0))||($index>cur+1&&(cur!=0||$index!=img_list.size()-1))'
由兩個大或(||)
組成
前面部分$index<cur-1&&(cur!=img_list.size()-1||$index!=0)
表示在cur-1
(左邊的可見)圖片以左的圖片,都會添加.hide
隱藏,除開一種狀況,當前指針在最後一張圖片那裏時,圖片列表中的第一張圖片不能添加.hide
,由於它將被添加.right
.
這裏利用了||運算符
的特色,若是第一個條件知足的話,就不會去斷定第二個條件;第一個條件不知足時,纔會去斷定第二個條件。
後面部分$index>cur+1&&(cur!=0||$index!=img_list.size()-1)
表示在cur+1
(右邊的可見)圖片以右的圖片,都會添加.hide
隱藏,除了當前指針在第一張圖片那裏時,圖片列表中的最後一張圖片不能添加.hide
,由於它將被添加.left
.
實際上,用離散數學裏的非(p且q)=非p或非q
就很好想了,除開已經添加了.left
,.middle
,.right
的圖片,剩下的就得添加.hide
,$index>cur+1
和$index<cur-1
能夠保證$index!=cur
.
而後是排除.left
,知足.left
的條件是$index==cur-1||(cur==0&&$index==img_list.size()-1)
,它的否認是$index!=cur-1&&(cur!=0||$index!=img_list.size()-1)
,這就和添加.hide
的條件的左邊部分同樣了。
排除.right
也是相似的。
把這兩個部分組合起來就能夠保證.left,.middle,.right,.hide這4個類之間是互斥的
。
固然也能夠利用css優先級
,讓.left
,.middle
,.right
類的優先級高於.hide
,這樣添加.hide
的斷定條件會簡單不少。爲了嚴謹些,就沒有用這種方式。
<div id='jump'> <ul> <li ms-repeat='img_list' ms-class-on='cur==$index'></li> </ul> </div>
cur==$index
讓'亮'的圓點和當前指針同步。
到這裏,任意改變roundabout.cur=?
均可以呈現roundabout佈局。
滾動過程當中,要滾動圖片有4種動畫狀態,以向右滾動爲例
左邊可見的圖片的上(左)一張圖片,不可見
=>在可見部分左邊,部分可見
原來左邊可見的圖片,在可見部分左邊,部分可見
=>中間,所有可見
原來中間所有可見的圖片,中間,所有可見
=>在可見部分右邊,部分可見
原來右邊可見的圖片,在可見部分右邊,部分可見
=>不可見
這裏用css3 animation
@keyframes to-right1 {//向右滾動 0% { width: 530px; height: 100px; opacity: 0; z-index: 0; margin-top: 85px; left: -530px; } 100% { width: 530px; height: 224px; opacity: 0.4; z-index: 1; margin-top: 23px; left: 0; } } @keyframes to-right2 { 0% { width: 530px; height: 224px; opacity: 0.4; z-index: 1; margin-top: 23px; left: 0; } 100% { width: 640px; height: 270px; opacity: 1; z-index: 2; margin-top: 0; left: 275px; } } @keyframes to-right3 { 0% { width: 640px; height: 270px; opacity: 1; z-index: 2; margin-top: 0; left: 275px; } 100% { width: 530px; height: 224px; opacity: 0.4; z-index: 1; margin-top: 23px; left: 660px; } } @keyframes to-right4 { 0% { width: 530px; height: 224px; opacity: 0.4; z-index: 1; margin-top: 23px; left: 660px; } 100% { width: 530px; height: 100px; opacity: 0; z-index: 0; margin-top: 85px; left: 1190px; } } ...
能夠看到,動畫無非是在.hide
,.left
,.middle
,.right
這4個狀態間切換。
@keyframes to-right1 {//向右滾動 0% { //.hide } 100% { //.left } } @keyframes to-right2{ 0% { //.left } 100% { //.middle } } @keyframes to-right3{ 0% { //middle } 100% { //right } } @keyframes to-right4{ 0% { //right } 100% { //hide1 } } ...
爲了方便編碼,用less
.state(@width,@height,@opacity,@z-index,@margin-top,@left){ width: @width; height: @height; opacity: @opacity; z-index: @z-index; margin-top: @margin-top; left:@left; } .middle(){ .state(640px,270px,1,2,0,275px); } .left(){ .state(530px,224px,0.4,1,23px,0); } .right(){ .state(530px,224px,0.4,1,23px,660px); } .hide(){ .state(530px,100px,0,0,85px,-530px); } .hide1(){ .state(530px,100px,0,0,85px,1190px); } .middle{ .middle(); } .left{ .left(); } .right{ .right(); } .hide{ .hide(); } @keyframes to-right1{//向右滾動 0% { .hide(); } 100% { .left(); } } @keyframes to-right2{ 0% { .left(); } 100% { .middle(); } } @keyframes to-right3{ 0% { .middle(); } 100% { .right(); } } @keyframes to-right4{ 0% { .right(); } 100% { .hide1(); } } ...
var roundabout=avalon.define({ $id:'roundabout', img_list:[], cur:0,//當前頁 jump:function(i,dir){//dir:滾動方向 roundabout.cur=i; } });
<div id='wrap' ms-controller='roundabout'> <div id='controls'> <a class='left_arrow' href="javascript:;" ms-click='jump(cur==0?img_list.size()-1:cur-1,1)'></a> <a class='right_arrow' href="javascript:;" ms-click='jump(cur==img_list.size()-1?0:cur+1,2)'></a> </div> ... </div>
jump
方法的dir參數後面會用到。
這裏尚未添加動畫類,只能進行沒有動畫的滾動。
//全部的動畫類 var animate_class='to-right1 to-right2 to-right3 to-right4 to-left1 to-left2 to-left3 to-left4'; ... jump:function(i,dir){ if(dir==1){//向右滾 cur-1 avalon($('img'+prev(i))).removeClass(animate_class).addClass('to-right1'); avalon($('img'+i)).removeClass(animate_class).addClass('to-right2'); avalon($('img'+next(i))).removeClass(animate_class).addClass('to-right3'); avalon($('img'+next(next(i)))).removeClass(animate_class).addClass('to-right4'); }else{//向左滾 cur+1 avalon($('img'+next(i))).removeClass(animate_class).addClass('to-left1'); avalon($('img'+i)).removeClass(animate_class).addClass('to-left2'); avalon($('img'+prev(i))).removeClass(animate_class).addClass('to-left3'); avalon($('img'+prev(prev(i)))).removeClass(animate_class).addClass('to-left4'); } roundabout.cur=i; } ... function prev(now){//上一頁 return now==0?roundabout.img_list.size()-1:now-1; } function next(now){//下一頁 return now==roundabout.img_list.size()-1?0:now+1; }
幾點說明
這裏的removeClass
方法和jquery中的同樣,當傳入參數像上面animate_class變量
,多個類以空格分開時,對目標刪除多個類(若是有的話)。
prev
,next
方法用來獲得上一張圖片和下一張圖片的在圖片列表中的索引.注意next(next(i))不等於next(i+1).
添加動畫類以前,要先刪除全部可能存在的動畫類。
和點擊左右箭頭,圖片滾動的動畫不同,這裏對目標圖片及其左右圖片是一個從小變大的動畫效果。
.state(@width,@height,@opacity,@z-index,@margin-top,@left){ width: @width; height: @height; opacity: @opacity; z-index: @z-index; margin-top: @margin-top; left:@left; } .jump-state(){ .state(0,0,0,0,135px,585px); } @keyframes jump-prev{//變小->左邊圖片 0% { .jump-state(); } 100% { .left(); } } @keyframes jump-middle{//變小->中間圖片 0% { .jump-state(); } 100% { .middle(); } } @keyframes jump-next{//變小->右邊圖片 0% { .jump-state(); } 100% { .right(); } }
下面對圓點綁定點擊事件
<div id='jump'> <ul> <li ms-repeat='img_list' ms-class-on='cur==$index' ms-click='spec_jump($index)'></li> </ul> </div>
spec_jump:function(i){ var cur=roundabout.cur; if(cur-prev(i)==0||cur-next(i)==0){//若是點擊的圖片是當前圖片或當前圖片的相鄰圖片 var dir=1;//肯定滾動方向 if(cur-prev(i)==0) dir=2; roundabout.jump(i,dir); }else{ roundabout.cur=i; avalon($('img'+prev(i))).removeClass(animate_class).addClass('jump-prev'); avalon($('img'+i)).removeClass(animate_class).addClass('jump-middle'); avalon($('img'+next(i))).removeClass(animate_class).addClass('jump-next'); } }
這裏會添加jump-prev
,jump-middle
,jump-next
類,因此前面的animate_class變量
也要加上這3個類。
js代碼不超過50行,固然css代碼多點,不過用less
寫的話,編程體驗很好