以前も当ブログでjQueryを使ったループスライダーを紹介しましたが、フリック(ドラッグ)操作が実装されていませんでした。

ループスライダーにフリック(ドラッグ)動作が実装されたパターンはわりと需要があるのに、そのような仕様のプラグイン等はあまり一般的に公開されていないようだったので、以前紹介したスクリプトを改良してフリック(ドラッグ)動作を実装したループスライダーを作成したので紹介してみます。

jQueryでフリック(ドラッグ)可能な要素が流れ続けるループスライダーを実装する方法

「jQueryでフリック(ドラッグ)可能な要素が流れ続けるループスライダーを実装する方法」サンプルを別枠で表示

Webページに並べられた要素が右から左へ流れ続けるループスライダーでスライダーをフリック(ドラッグ)することができます。

動作自体はただひたすら要素が流れ続けるシンプルなものです。

全体構成についてまずはHTMLから。

◆HTML
<div class="loopSlider">
<ul>
<li><a href="https://www.black-flag.net/"><img src="img/photo1.jpg" alt=""></a></li>
<li><a href="https://www.google.co.jp/"><img src="img/photo2.jpg" alt=""></a></li>
<li><a href="https://www.yahoo.co.jp/"><img src="img/photo3.jpg" alt=""></a></li>
<li><img src="img/photo4.jpg" alt=""></li>
<li><img src="img/photo5.jpg" alt=""></li>
<li><img src="img/photo6.jpg" alt=""></li>
<li><img src="img/photo7.jpg" alt=""></li>
<li><img src="img/photo8.jpg" alt=""></li>
<li><img src="img/photo9.jpg" alt=""></li>
<li><img src="img/photo10.jpg" alt=""></li>
</ul>
</div><!--/.loopSlider-->

スライド動作させる要素は<ul>を使ってリストで構成しそのリスト全体は任意のブロック要素で囲います。

リストの中の要素にリンクを貼ることも当然のことながら可能になっているので、動作サンプルとして最初の3つのリストのみ<a>タグを設定しています。
不要な場合は外してしまって問題ありません。

この要素に対してCSSは以下のように指定します。

◆CSS
/* ------------------------------
   loopSlider
------------------------------ */
.loopSliderWrap {
	top: 0;
	left: 0;
	height: 300px;
	overflow: hidden;
	position: absolute;
}

.loopSliderWrap:after {
	content: "";
	display: block;
	clear: both;
}

.loopSlider {
	margin: 0 auto;
	width: 100%;
	height: 300px;
	text-align: left;
	position: relative;
	overflow: hidden;
	visibility: hidden;
}

.loopSlider ul {
	height: 300px;
	float: left;
	overflow: hidden;
}

.loopSlider ul li {
	width: 300px;
	height: 300px;
	float: left;
	overflow: hidden;
}

.loopSlider ul li img {
	width: 100%;
	height: 100%;
}

@media only screen and (max-width: 768px) {
	.loopSliderWrap,
	.loopSlider,
	.loopSlider ul {
		height: 100px;
	}

	.loopSlider ul li {
		width: 100px;
		height: 100px;
	}
}

一番最初にある「.loopSliderWrap」はスクリプト側から生成するブロック要素になり、このセレクタに対しては表示するスライダーの高さを指定しておきます。

HTML側でリスト全体を囲んだブロック要素「.loopSlider」には要素がスライドする際の、表示する領域の幅と高さを指定します。

メディアクエリーではSP時のループスライダーのサイズを指定します。

そして、実際のフリック(ドラッグ)動作付きのループスライダースクリプトは以下の様になります。

◆SCRIPT
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
<script>
$(function(){
	let setElm = $('.loopSlider'),
	moveInterval = 3,
	slideTimeBase = 10,
	spWidth = 768,
	spSpeed = 3;

	$(window).on('load', function(){
		setElm.each(function(){
			let self = $(this),
			selfWidth = self.innerWidth(),
			findUl = self.find('ul'),
			findLi = findUl.find('li'),
			findLink = findLi.find('a'),
			listCount = findLi.length;

			listWidth = findLi.outerWidth();
			loopWidth = listWidth * listCount;

			findUl.wrapAll('<div class="loopSliderWrap" />');
			let selfWrap = self.find('.loopSliderWrap');

			setElm.css({visibility:'visible',opacity:'0'}).animate({opacity:'1'},500);

			if(loopWidth > selfWidth){
				findUl.css({width:loopWidth}).clone().appendTo(selfWrap).clone().prependTo(selfWrap);

				selfWrap.css({left:'-' + loopWidth + 'px'});

				setSlideTime();
				timerLeft();

				$(window).on('resize', function(){
					clearInterval(setTimer);
					setSlideTime();
					timerLeft();
				}).resize();

				function setSlideTime() {
					if(window.innerWidth > spWidth){
						slideTime = slideTimeBase;
					} else {
						slideTime = slideTimeBase*spSpeed;
					}
				}

				function timerLeft(){
					setTimer = setInterval(function(){loopPositionLeft()},slideTime);
				};

				function loopPositionLeft(){
					listWidth = findLi.outerWidth();
					loopWidth = listWidth * listCount;

					self.find('ul').css({width:loopWidth});
					selfWrap.css({width:loopWidth*3}).stop().animate({left:'-=' + (moveInterval) + 'px'},slideTime,'linear',function(){
						let posLeft = parseInt(selfWrap.css('left')),
						widthCal = (loopWidth)-((loopWidth)*3);
						if (posLeft <= widthCal) {
							let calCat = posLeft - widthCal;
							//alert(calCat)
							selfWrap.css({left:'-' + (loopWidth - calCat) + 'px'});
						}
					});
					return false;
				};

				function myHandler(e){
					e.preventDefault();
				}

				let isTouch = ('ontouchstart' in window),
				ua = navigator.userAgent;

				selfWrap.on({
					'touchstart mousedown': function(e){
						if(!(ua.search(/iPhone/) != -1 || ua.search(/iPad/) != -1 || ua.search(/Macintosh/) != -1 && 'ontouchend' in document || ua.search(/iPod/) != -1 || ua.search(/Android/) != -1)){
							e.preventDefault();
							$(this).find('a').off('click', myHandler);
						}
						if(selfWrap.is(':animated')){
							clearInterval(setTimer);
						}
						this.pageX = (isTouch ? event.changedTouches&#91;0&#93;.pageX : e.pageX);
						this.leftBegin = parseInt($(this).css('left'));
						this.left = parseInt($(this).css('left'));
						this.touched = true;
					},
					'touchmove mousemove': function(e){
						if(!this.touched){return;}
						if(!(ua.search(/iPhone/) != -1 || ua.search(/iPad/) != -1 || ua.search(/Macintosh/) != -1 && 'ontouchend' in document || ua.search(/iPod/) != -1 || ua.search(/Android/) != -1)){
							e.preventDefault();
							$(this).find('a').on('click', myHandler);
						}
						if(selfWrap.is(':animated')){
							clearInterval(setTimer);
						}
						this.left = this.left - (this.pageX - (isTouch ? event.changedTouches&#91;0&#93;.pageX : e.pageX) );
						this.pageX = (isTouch ? event.changedTouches&#91;0&#93;.pageX : e.pageX);
						$(this).css({left:this.left});
					},
					'touchend mouseup mouseout': function(e){
						if (!this.touched) {return;}
						this.touched = false;

						outLeft = parseInt($(this).css('left'));
						if(outLeft < (loopWidth)-((loopWidth)*3)){
							$(this).css({left: outLeft - (loopWidth-(loopWidth*2)) + 'px'});
						}
						if(outLeft > (loopWidth)-((loopWidth)*2)){
							$(this).css({left: outLeft + (loopWidth-(loopWidth*2)) + 'px'});
						}

						timerLeft();
						return false;
					}
				});

				if(ua.search(/iPhone/) != -1 || ua.search(/iPad/) != -1 || ua.search(/Macintosh/) != -1 && 'ontouchend' in document || ua.search(/iPod/) != -1 || ua.search(/Android/) != -1){
					selfWrap.find('a').on({
						'touchstart': function(e){
							thisHref = $(this).attr('href');
							thisTarget = $(this).attr('target');
							touchFlag = true;
						},
						'touchmove': function(e){
							touchFlag = false;
							e.preventDefault();
						},
						'touchend': function(e){
							if(touchFlag == true){
								if(thisTarget == '_blank'){
									window.open(thisHref, '_blank');
								} else {
									location.href = thisHref;
								}
							}
						}
					});
				}
			}
		});
	});
});
</script>

スクリプト開始部分にある設定値の内容は以下の様になっています。

setElm = $(‘.loopSlider’) スライド全体を囲うブロック要素(IDでも可)
moveInterval = 3 スライダーが進む距離
slideTimeBase = 10 moveIntervalで設定した距離を進む時間
spWidth = 768 SPサイズに変わる幅
spSpeed = 3 SPサイズになった際のスライド時間

「moveInterval」スライダーが一度に進む距離(px)になっており、「slideTimeBase」が「moveInterval」で指定した距離を進むスピードの設定になり、この2つの値でループスライダーのスピードを調整します。

「spWidth」はSPサイズに変わるウィンドウサイズの幅を指定し、「spSpeed」ではPCサイズとSPサイズでのリストサイズの割合を指定してスピードを調整します。
サンプルではSP時のループスライダーのリストはPC時のリストの三分の一のサイズにしているので、ここでは「3」を指定しています。

少々、スピードの設定が特殊な作りになってしまっていますが、これらの値を変更することでループスライダーのスピード調整ができるようになっています。

以上がフリック(ドラッグ)可能な要素が流れ続けるループスライダーを実装する方法でした。

SP用としてループスライダーを設置する場合は、フリック(ドラッグ)操作はほぼ必須になってくるので、このようなレスポンシブ対応したループスライダーはお役立ていただけるかと思っています。

フリック(ドラッグ)可能なループスライダーを設置する際にぜひ。。。

サンプルファイルをダウンロードしたい方はこちらから