みかづきブログ その3

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

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

SCSSのmixinにしてみました。


DEMO

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


HTML

<div data-carousel="0">
    <ol class="photos">
        <li class="photo"></li>
        <li class="photo"></li>
        <li class="photo"></li>
        <li class="photo"></li>
    </ol>
    <ol class="btns">
        <li class="btn"></li>
        <li class="btn"></li>
        <li class="btn"></li>
        <li class="btn"></li>
    </ol>
</div>

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;
        transition: left .6s ease-in-out;
    }

    .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 0 through ($length) {
        &[data-carousel="#{$i}"] {
            .photos {
                left: $i * -100%;
            }

            .btn:nth-child(#{$i + 1}) {
                background: rgba(255, 255, 255, 1);
            }
        }
    }
}

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

.photo {
    &:nth-child(1) {
        background: #c3c3c3;
    }
    
    &:nth-child(2) {
        background: #a3a3a3;
    }
    
    &:nth-child(3) {
        background: #838383;
    }
    
    &:nth-child(4) {
        background: #636363;
    }
}

JavaScript

(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.width(that.length * 100 + "%");
    that.$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.css("opacity", 1); // for Android
    that.$btn.css("opacity", 1); // for Android
 
    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.index + 1) % that.length;
    that._show();
  };

  Carousel.prototype.prev = function() {
    var that = this;
 
    if (that.length < 2) {
      return;
    }

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