Puree網站的1大六小廣告區實作

動機

這大概是四個月前寫的東西了。當時有客戶覺得 PUREE 首頁左邊那個活動廣告很不錯,他也想要網站有這個功能。稍微看了一下覺得並不難做,便在半好玩的心態下將它完成了。不過後來客戶又說他不需要了,結果這個小作品就一直被擱置在角落最後就被忘掉了。剛剛在整理檔案時又發現了它,現在重新看看覺得還蠻好玩的,勉強算是個可以用的東西,就在這邊和大家分享一下囉。

分析

該套件大概粗分三大部分功能:

  1. 上面比較大的那塊是個簡單的水平方向的圖片輪播
  2. 下方六小格在滑鼠移動上去時,上方區域的圖片會移動到對應的編號
  3. 有個移動的框框會移動到滑鼠最後滑上去的六小格上

步驟

1. 靜態的 html 以及 css
puree.html
<!doctype html>
<html lang="zh-tw">
<head>
    <meta charset="UTF-8">
    <title>六方格+換圖片動畫</title>
    <link rel="stylesheet" href="css/reset.css" />
    <link rel="stylesheet" href="css/puree.css" />
</head>
<body>
<!-- 
主要達成功能:
=======================================================================
當滑鼠移動到下方的小圖片( 其實是事件是綁在div )上時,大塊的地方會動態切換到對應標號的圖片( 其實是換div ),例子裡只有文字,
大家要用的話自行將文字改為圖片即可。
-->
<div class="puree_six_ad" >
    <div class="top">
        <div class="gallery">
            <div>1.</div>
            <div>2.</div>
            <div>3.</div>
            <div>4.</div>
            <div>5.</div>
            <div>6.</div>
        </div>
    </div>
    <div class="bottom">
        <div>1.</div>
        <div>2.</div>
        <div>3.</div>
        <div>4.</div>
        <div>5.</div>
        <div>6.</div>
    </div>
</div>
</body>
</html>
css/puree.css
div.puree_six_ad {
  position: absolute;
  width: 260px;
  height: 550px;
  margin: 20px 0 20px 200px;
  border: red solid 2px;
  overflow: hidden; }
  div.puree_six_ad div.top {
    width: 260px;
    height: 300px;
    border: yellow solid 1px; }
    div.puree_six_ad div.top div.gallery {
      position: absolute;
      width: 1560px;
      height: 300px; }
      div.puree_six_ad div.top div.gallery div {
        float: left;
        width: 260px;
        height: 300px; }
div.bottom div {
  width: 80px;
  height: 104px;
  float: left;
  border-right: #dedede 1px solid;
  margin: 5px 0 3px 5px; }
  div.bottom div:nth-of-type(3), div.bottom div:last-of-type {
    border-style: none; }
div.float_frame {
  position: absolute;
  border: black 2px solid; }

完成後應該可以看到這樣的畫面:

2. 實作功能分析中的第一項功能-水平輪播
引入javascript
puree.html
<script src="js/jquery-1.9.1.js"></script>
<script src="js/puree.js"></script>

撰寫 javascript
js/puree.js
jQuery(function ($) {

    var view = {};// 宣告視圖物件


    /* 將需要用到的 DOM 元素存進 view 裡頭 */
    view.$all = $('.puree_six_ad'); // 整個廣告區塊

    view.$top = view.$all.find('.top'); // 圖片輪播區域

    view.$gallery = view.$top.find('.gallery'); // 圖片輪播區域中的圖片區塊

    view.$eachPic = view.$gallery.children(); // 各張輪播圖片

    view.$bottom = view.$all.find('.bottom'); // 底部區塊,包含六個 div( 即六小圖區域 )

    view.$sixSmall = view.$bottom.children(); // 六小圖


    /* 先將之後動畫必定會用到的一些數值求出 */
    view.nTopWidth = parseInt( view.$top.width() ); // 輪播圖片外框寬度

    view.nGalleryWith = parseInt( view.$gallery.width() ); // 輪播圖片寬度

    view.nShift = (view.nGalleryWith - view.nTopWidth); // 寬度差,用來判斷是否已經輪播到最後一張圖片

  
  /* 浮動框框會用到,先在這邊求出 */
  view.nSmallMarginLeft = parseInt(view.$sixSmall.eq(0).css('marginLeft')); // 六小圖 marginTop 的值

    view.nSmallMarginTop = parseInt(view.$sixSmall.eq(0).css('marginTop')); // 六小圖 marginLeft 的值


    var config = {}; // 宣告參數物件

    config.nSpeed = 500;
    config.nTimeInterval = 2000;

    // 利用改變 css 的 'left' 屬性數值實現圖片換張的效果

    var autoGalleryPlay = function () {
        view.autoRun = setTimeout(function () {

            // 取得目前 $gallery 的 css 'left' 屬性值 

            var nNowLeft = parseInt( view.$gallery.css( 'left' ), 10 );
            
            // 切換圖片動畫

            view.$gallery.stop().animate({
                // 計算切換到下一張圖片時應該改變的 left 值

                left: getNextLeft( isNaN( nNowLeft ) ? 0 : nNowLeft )
            }, config.nSpeed, function () {
                autoGalleryPlay(); // 遞迴執行播放動作

            });      
        }, config.nTimeInterval );
    };

    /**
     * 取得下一次輪播需要的 left 屬性數值 
     * @param  {[number]} nNowLeft [目前內框的 left 值]
     * @return {[number]}          
     */
    var getNextLeft = function ( nNowLeft ) {
        // 如果左移量已經比內外區塊寬度差還大,表示為最後一張圖片:

        // true: 表示為最後一張圖片,回傳0回到第一張

        // false: 則左移一個父框寬度,切換到下一張

        return ((view.nShift + nNowLeft) <= 0) ? 0 : (nNowLeft - view.nTopWidth);         
    };

    // 啟動輪播

    autoGalleryPlay();
});  

測試後確定輪播效果正常呈現,再來就是讓我們加上滑鼠移到整個廣告區塊時,暫停輪播的事件:
請將 "// 啟動輪播" 以後的程式碼改成這樣:

js/puree.js
//...


// 綁定啟動輪播事件以及取消輪播事件 

view.$all.mouseover(function () {
    return clearTimeout( view.autoRun );
}).mouseleave(function () {
    return autoGalleryPlay();
}).mouseleave();// DOM讀取完成後自動 onFire 觸發輪播動作


重整後試試看把您的滑鼠移到廣告區塊時,動畫有沒有停止呢?
如果有,那恭喜您,輪播功能差不多 ok 拉!接下來實作六小圖控制上方輪播圖片的功能吧 ~
( 如果沒有,或是圖片根本一開始就不會輪播了,請打開主控台檢查有無錯誤 )

3. 實作分析功能中的第二項功能-選擇顯示輪播圖片

請在您的 puree.js 最下方追加以下程式碼:

js/puree.js
// ...


    /*
        滑鼠移到六小圖上後,輪播圖片切換到對應的圖片      
        1. 先抓出小圖在兄弟元素中的索引值( 第幾個 )
        2. 該索引值乘以父框寬度即輪播圖片應變換的 'left' 值,
        更清楚講就是,假個該小圖是第 n 張圖,則上方輪播區域就需要移動 (n - 1) 個父元素寬度 
     */ 
    view.$sixSmall.mouseover(function () {
        var nIndex = $(this).index();

      view.$gallery.stop().animate({
        left: -(nIndex * view.nTopWidth) 
      }, config.nSpeed );  
    }).on('mouseover.anifloatFrame', function () {
        view.$floatFrame.stop().animate({
            'top': $(this).offset().top - view.nSmallMarginTop,
            'left': $(this).offset().left - view.nSmallMarginLeft
        }, config.nMouseSpeed );       
    });

現在把滑鼠移到下方得六小圖,上面的輪播區域也會跟著移動囉。
測試看看吧,如果沒有問題就前往最後一步吧。

4. 實作分析功能中的第三項功能-浮動框框

這邊的作法大概是這樣的:

1.用 jQuery 加上一個 div元素,就是我們的框框
js/puree.js
//...


view.$floatFrame = $(document.createElement('div')); // 產生浮動框框div


/*
1. 加上 class = float_frame
2. 將它放入body
3. 擺在第一個六小圖上,並且配置相關 css 屬性值
*/
view.$floatFrame.addClass('float_frame').appendTo('body').css({
    top: view.$sixSmall.eq(0).offset().top - view.nSmallMarginTop,
    left: view.$sixSmall.eq(0).offset().left - view.nSmallMarginLeft,
    width: view.$sixSmall.outerWidth(),
    height: view.$sixSmall.outerHeight(true)
});

2.綁定滑鼠移動到六小圖上時,框框會跟著移動的動畫

請將 view.$sixSmall 的綁定事件改成如下程式碼

  /*
        switchGallery:
        滑鼠移到六小圖上後,輪播圖片切換到對應的圖片      
        1. 先抓出小圖在兄弟元素中的索引值( 第幾個 )
        2. 該索引值乘以父框寬度即輪播圖片應變換的 'left' 值,
        更清楚講就是,假個該小圖是第 n 張圖,則上方輪播區域就需要移動 (n - 1) 個父元素寬度 

        aniFloatFrame:
        讓浮動框框移動到現在滑鼠上方的六小圖
     */ 
    view.$sixSmall.on('mouseover.switchGallery', function () {
        var nIndex = $(this).index();

      view.$gallery.stop().animate({
        left: -(nIndex * view.nTopWidth) 
      }, config.nSpeed );  
    }).on('mouseover.anifloatFrame', function () {
        view.$floatFrame.stop().animate({
            'top': $(this).offset().top - view.nSmallMarginTop,
            'left': $(this).offset().left - view.nSmallMarginLeft
        }, config.nMouseSpeed );       
    });

浮動框框會跑來跑去囉~~

3.浮動框框造成的小錯誤修正

由於框框是加上去的,所以會蓋在六小圖上,這會導致取消輪播事件無法觸發,所以取消的事件觸發元素要把框框加上去。
找到取消輪播事件的程式碼,改成如下:

    // 綁定啟動輪播事件以及取消輪播事件 

    view.$all.add(view.$floatFrame).mouseover(function () {
        return clearTimeout( view.autoRun );
    }).mouseleave(function () {
        return autoGalleryPlay();
    }).mouseleave();

OK!該有的功能都齊備了!
不過我們可以做得更好,現在把程式碼加進 jQuery方法變成誰都會用的小套件吧!
將檔案改成 jquery.sixad_crausel.js,並且整理得更好閱讀一點。請將程式碼改成如下:

js/jquery.sixad_crausel.js
;(function ($) {

  $.fn.sixadCrausel = function () {
    var SixAD = function ($e) {
      this.view = {};// 宣告視圖物件

      this.config = {};// 宣告參數物件

      return this.init($e);
    };

    /**
     * 將需要用到的 DOM 元素存進 view 裡頭
     * @param  [jQuery Obj]
     * @return this 
     */
    SixAD.prototype.setView = function ($e) {
      var view = this.view;
      view.$all = $e; // 整個廣告區塊

      view.$top = view.$all.find('.top'); // 圖片輪播區域

      view.$gallery = view.$top.find('.gallery'); // 圖片輪播區域中的圖片區塊

      view.$eachPic = view.$gallery.children(); // 各張輪播圖片

      view.$bottom = view.$all.find('.bottom'); // 底部區塊,包含六個 div( 即六小圖區域 )

      view.$sixSmall = view.$bottom.children(); // 六小圖


      /* 先將之後動畫必定會用到的一些數值求出 */
      view.nTopWidth = parseInt( view.$top.width() ); // 輪播圖片外框寬度

      view.nGalleryWith = parseInt( view.$gallery.width() ); // 輪播圖片寬度

      view.nShift = (view.nGalleryWith - view.nTopWidth); // 寬度差,用來判斷是否已經輪播到最後一張圖片


      /* 浮動框框會用到,先在這邊求出 */
      view.nSmallMarginLeft = parseInt(view.$sixSmall.eq(0).css('marginLeft')); // 六小圖 marginTop 的值

      view.nSmallMarginTop = parseInt(view.$sixSmall.eq(0).css('marginTop')); // 六小圖 marginLeft 的值

      return this;
    };

    /**
     * 設定動畫相關參數
     */
    SixAD.prototype.setConfig = function () {
      this.config.nSpeed = 500;
      this.config.nTimeInterval = 2000;
      return this;
    };

    // 利用改變 css 的 'left' 屬性數值實現圖片換張的效果

    SixAD.prototype.autoGalleryPlay = function () {
      var self = this,
          view = self.view;
      view.autoRun = setTimeout(function () {
        // 取得目前 $gallery 的 css 'left' 屬性值 

        var nLeft = parseInt( view.$gallery.css( 'left' ), 10 );
        // 切換圖片動畫

        self.switchImgAnimate( isNaN( nLeft ) ? 0 : nLeft );
      }, self.config.nTimeInterval );
    };

    /**
     * 切換圖片動畫
     *
     * @param  [number] nLeft
     * @return this
     */
    SixAD.prototype.switchImgAnimate = function ( nLeft ) {
      var self = this,
          view = self.view;
      // 切換圖片動畫

      view.$gallery.stop().animate({
        // 計算切換到下一張圖片時應該改變的 left 值

        left: self.getNextLeft( nLeft )
      }, self.config.nSpeed, function () {
        self.autoGalleryPlay(); // 遞迴執行播放動作

      });   
    };

    /**
     * 取得下一次輪播需要的 left 屬性數值 
     * @param  {[number]} nNowLeft [目前內框的 left 值]
     * @return {[number]}          
     */
    SixAD.prototype.getNextLeft = function ( nNowLeft ) {
      var view = this.view;
      // 如果左移量已經比內外區塊寬度差還大,表示為最後一張圖片:

      // true: 表示為最後一張圖片,回傳0回到第一張

      // false: 則左移一個父框寬度,切換到下一張

      return ((view.nShift + nNowLeft) <= 0) ? 0 : (nNowLeft - view.nTopWidth);     
    };

    /**
     * 綁定啟動輪播事件以及取消輪播事件
     * @return this
     */
    SixAD.prototype.bindTimerControll = function () {
      var self = this,
          view = self.view;
      view.$all.add(view.$floatFrame).mouseover(function () {
        return clearTimeout( view.autoRun );
      }).mouseleave(function () {
        return self.autoGalleryPlay();
      }).mouseleave();
      return this;
    };

    /**
     * 產生浮動框框並且放置於指定位置
     * @return this
     */
    SixAD.prototype.genFloatFrame = function () {
      var view = this.view;
      view.$floatFrame = $(document.createElement('div')); // 產生浮動框框div

    
      /*
        1. 加上 class = float_frame
        2. 將它放入body
        3. 擺在第一個六小圖上,並且配置相關 css 屬性值
       */
      view.$floatFrame.addClass('float_frame').appendTo('body').css({
        top: view.$sixSmall.eq(0).offset().top - view.nSmallMarginTop,
        left: view.$sixSmall.eq(0).offset().left - view.nSmallMarginLeft,
        width: view.$sixSmall.outerWidth(),
        height: view.$sixSmall.outerHeight(true)
      });
      return this;
    };

    /*
      switchGallery:
      滑鼠移到六小圖上後,輪播圖片切換到對應的圖片    
      1. 先抓出小圖在兄弟元素中的索引值( 第幾個 )
      2. 該索引值乘以父框寬度即輪播圖片應變換的 'left' 值,
      更清楚講就是,假個該小圖是第 n 張圖,則上方輪播區域就需要移動 (n - 1) 個父元素寬度 

      aniFloatFrame:
      讓浮動框框移動到現在滑鼠上方的六小圖
     */ 
    SixAD.prototype.bindSixSmallEvent = function () {
      var self = this,
          view = this.view;
      view.$sixSmall.on('mouseover.switchGallery', function () {
        var nIndex = $(this).index();

        view.$gallery.stop().animate({
          left: -(nIndex * view.nTopWidth) 
        }, self.config.nSpeed );  
      }).on('mouseover.anifloatFrame', function () {
        view.$floatFrame.stop().animate({
          'top': $(this).offset().top - view.nSmallMarginTop,
          'left': $(this).offset().left - view.nSmallMarginLeft
        }, self.config.nMouseSpeed );   
      });
      return this;
    };

    // 初始化廣告區域程式

    SixAD.prototype.init = function ($e) {
      this.setView($e).setConfig().genFloatFrame().bindSixSmallEvent().bindTimerControll();
      return $e;
    };

    return new SixAD(this);
  };

})(jQuery); 

puree.html
<!doctype html>
<html lang="zh-tw">
<head>
    <meta charset="UTF-8">
    <title>六方格+換圖片動畫</title>
    <link rel="stylesheet" href="css/reset.css" />
    <link rel="stylesheet" href="css/puree.css" />
    <script src="js/jquery-1.9.1.js"></script>
    <script src="js/jquery.sixad_crausel.js"></script>
</head>
<body>
<!-- 
主要達成功能:
=======================================================================
當滑鼠移動到下方的小圖片( 其實是事件是綁在div )上時,
大塊的地方會動態切換到對應標號的圖片( 其實是換div ),例子裡只有文字,
大家要用的話自行將文字改為圖片即可。
-->
<div class="puree_six_ad">
    <div class="top">
        <div class="gallery">
            <div>1.</div>
            <div>2.</div>
            <div>3.</div>
            <div>4.</div>
            <div>5.</div>
            <div>6.</div>
        </div>
    </div>
    <div class="bottom">
        <div>1.</div>
        <div>2.</div>
        <div>3.</div>
        <div>4.</div>
        <div>5.</div>
        <div>6.</div>
    </div>
</div>
<script>
jQuery(function ($) {
    $('.puree_six_ad').sixadCrausel();
});
</script>
</body>
</html>

DEMO連結

Comments

comments powered by Disqus