以前制作したスマフォ用カルーセル ですが、関係各所からの要望により、先頭と最後をループさせるように改良しました。
方針としては、
- 先頭と最後尾にループ用の要素を増やす
- jQueryのanimateでスクロールさせる(コールバックを登録するため)
- ループ用の要素へスクロールした際は先頭 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
※ スマートフォンでしか動作しません