avalon js+css3實現roundabout 圖片輪播

roundabout效果

效果就像優酷綜藝頻道頁面的圖片輪播。
本屌以前作過這個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張圖片,這裏類名.hidecss3

.hide {
  width: 530px;
  height: 100px;
  opacity: 0;
  z-index: 0;
  margin-top: 0;
  left: -530px;
}
  • 可見的3張圖片,按位置具體可分爲.left,.middle,.rightgit

.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=>.middleless

  • 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佈局。

圖片滾動

定義css3 animation

滾動過程當中,要滾動圖片有4種動畫狀態,以向右滾動爲例

  1. 左邊可見的圖片的上(左)一張圖片,不可見=>在可見部分左邊,部分可見

  2. 原來左邊可見的圖片,在可見部分左邊,部分可見=>中間,所有可見

  3. 原來中間所有可見的圖片,中間,所有可見=>在可見部分右邊,部分可見

  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寫的話,編程體驗很好


下載

相關文章
相關標籤/搜索