みかづきブログ その3

3ヶ月つづけてみました。

スマフォ用軽量カルーセルをつくろう その2

kimizuka.hatenablog.com

以前制作したスマフォ用カルーセル ですが、関係各所からの要望により、先頭と最後をループさせるように改良しました。

方針としては、

  1. 先頭と最後尾にループ用の要素を増やす
  2. jQueryのanimateでスクロールさせる(コールバックを登録するため)
  3. ループ用の要素へスクロールした際は先頭 or 最後尾に飛ばす

という具合です。

JSとCSSでもろもろ調整したので、HTMLは編集することなくつかえます。

JavaScript

// forked from kimmy's "カルーセルをつくろう" http://jsdo.it/kimmy/w9Gt
(function buildCarousel(win, doc, $) {
 
  "use strict";
 
  function Carousel($elm) {
    var that  = this,
        diff  = 0,
        x     = 0,
        LIMIT = 100;
 
    that.$elm     = $elm;
    that.$photos  = $elm.find(".photos"),
    that.$photo   = $elm.find(".photo"),
    that.$btn     = $elm.find(".btn"),
    that.index    = $elm.attr("data-carousel") - 0 || 0;
    that.length   = $elm.find(".photo").length;
    that.max      = that.length - 1;
    that.timer    = null;
    that.INTERVAL = 5000;
      
    $elm.on("touchstart", _start);
    $elm.on("touchend", _end);
 
    that.$photos.prepend(that.$photo.last().clone());
    that.$photos.append(that.$photo.eq(0).clone());

    // コピーしたDOM分調整
    that.index  += 1;
    that.length += 2;
    that.max    += 2;
      
    that.$photos.width(that.length * 100 + "%");
    $elm.find(".photo").width(100 / that.length + "%");

    that._show();
 
    function _start(evt) {
      x = evt.originalEvent.touches[0].pageX;
    }
 
    function _end(evt) {
      diff = x - evt.originalEvent.changedTouches[0].pageX;
 
      if (diff > LIMIT) {
        that.next();
      } else if (diff < -LIMIT) {
        that.prev();
      }
    }
  }

  Carousel.prototype._show = function() {
    var that = this;

    that.$elm.attr("data-carousel", that.index);
    that.$photos.animate({ // jQueryのanimateに変更
      left : that.index * -100 + "%"
    }, function() {
      switch (that.index) { // 先頭 or 最後のときにループさせる処理
        case 0:
          that.index = that.max - 1;
          break;
        case that.max:
          that.index = 1;
          break;
      }

      that.$photos.css({
        left : that.index * -100 + "%"
      });

    });

    if (that.length > 1) {
      clearInterval(that.timer);
      that.timer = setTimeout(that.next.bind(that), that.INTERVAL);
    }
  };

  Carousel.prototype.next = function() { // 単純なインクリメントに変更
    var that = this;

    if (that.length < 2) {
      return;
    } 

    ++that.index;

    that._show();
  };

  Carousel.prototype.prev = function() { // 単純なデクリメントに変更
    var that = this;
 
    if (that.length < 2) {
      return;
    }

    --that.index;

    that._show();
  };
 
  $(function() {
    var $carousel = $("[data-carousel]");
   
    $carousel.each(function(index) {
      new Carousel($carousel.eq(index));
    });
  });
 
})(this, document, jQuery);

SCSS

@import "compass/reset";

body {
    background: #e3e3e3;
}

@mixin carousel($length) {
    position: relative;
    width: 100%;
    background: #3e3e3e;
    overflow: hidden;

    .photos {
        box-sizing: border-box;
        position: relative;
        padding-bottom: 16px;
        width: $length * 100%;
        height: 100%;
        overflow: hidden;
    }

    .photo {
        float: left;
        width: 100 / $length - 0%;
        height: 100%;
        background-position: center center;
        background-size: cover;
    }

    .btns {
        position: absolute;
        bottom: 0; left: 0;
        width: 100%; height: 16px;
        font-size: 10px;
        text-align: center;
    }

    .btn {
        display: inline-block;
        border-radius: 50%; // 【TODO】Android 2.X で不安
        margin: 0 2px;
        width: 5px; height: 5px;
        background: rgba(255, 255, 255, .5);
        cursor: pointer;
    }

    @for $i from 1 through $length {
        &[data-carousel="#{$i}"] {
            .btn:nth-child(#{$i}) {
                background: rgba(255, 255, 255, 1);
            }
        }
        
        &[data-carousel="0"] { // ループ用
            .btn:last-child {
                background: rgba(255, 255, 255, 1);
            }
        }
        
        &[data-carousel="#{$length + 1}"] { // ループ用
            .btn:first-child {
                background: rgba(255, 255, 255, 1);
            }
        }
    }
}

[data-carousel] {
    @include carousel(4);
    height: 300px;
}

.photo { // 最初と最後はループ用
    &:nth-child(2), &:last-child {
        background: #c3c3c3;
    }
    
    &:nth-child(3) {
        background: #a3a3a3;
    }
    
    &:nth-child(4) {
        background: #838383;
    }
        
    &:nth-child(5), &:first-child {
        background: #636363;
    }
}

DEMO


※ スマートフォンでしか動作しません