Bootstrap4のカルーセルをタッチ操作に対応させる【jQuery】

関連タグ:

公開日:

最終更新日:

Bootstrap4のカルーセルをタッチ操作に対応させる【jQuery】

いつも私がかかっている案件は基本的にCSSフレームワークは使用せず、1からコーディングを初めていくことが多いのですが、たまたまBootstrapをベースにしてデザインとレイアウトを組んでいくことがあったので、その備忘録です。

その際に、カルーセル(画像スライド)を設置することになったのですが、iPhoneでの実機検証中にタッチ・スワイプ操作でのスライドができなかったので、jQueryで別途で動作を加えて対応させた「タッチ操作でも反応するカルーセル」について書きたいと思います。

※Bootstrap4.2以降はタッチ操作にも対応しているようでした。
https://getbootstrap.com/docs/4.2/components/carousel/#options

Bootstrapの導入とカルーセルの設置

言うまでもないですが、まずBootstrapを使うために各種ファイルを設置します。
以下は構築当時のソースコードをコピペしただけなので、任意に変更してください。

<!-- ↓headタグ内に設置 -->
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
<!-- ↓body閉じタグ前に設置 -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="/assets/js/bootstrap.min.js"></script>
<!-- ↓今回のタッチ操作のために設置したJS -->
<script src="/assets/js/bootstrap.carousel-swipe.js"></script>

各種ファイルの設置ができれば、あとはHTMLファイルにカルーセルの設置をします。
Bootstrapを導入して入れば、「carousel」クラスを設定するだけで自動的にカルーセルのデフォルト設定が適用されます。

もう一点、「active」クラスを設定(以下のコードではcarousel-itemの1番目)しないとうまく表示されないので注意してください。

公式には複数のカルーセルを設定する場合は固有のIDをそれぞれに設定すると解説がありますが、1つの場合でも設定しておく方が判別がつきやすいと思います。

以下は公式のコピペなので任意のソースコードで変更してください。

<div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
  <ol class="carousel-indicators">
    <li data-target="#carouselExampleIndicators" data-slide-to="0" class="active"></li>
    <li data-target="#carouselExampleIndicators" data-slide-to="1"></li>
    <li data-target="#carouselExampleIndicators" data-slide-to="2"></li>
  </ol>
  <div class="carousel-inner">
    <div class="carousel-item active">
      <img src="..." class="d-block w-100" alt="...">
    </div>
    <div class="carousel-item">
      <img src="..." class="d-block w-100" alt="...">
    </div>
    <div class="carousel-item">
      <img src="..." class="d-block w-100" alt="...">
    </div>
  </div>
  <a class="carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev">
    <span class="carousel-control-prev-icon" aria-hidden="true"></span>
    <span class="sr-only">Previous;</span>
  </a>
  <a class="carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next">
    <span class="carousel-control-next-icon" aria-hidden="true"></span>
    <span class="sr-only">Next;</span>
  </a>
</div>

うまく動いていればBootstrapの導入もカルーセルの設置もできているので次に進みます。
動いていない場合はスクリプトのパスが間違っていたり、HTMLのコードにシンタックスエラーが出ていたりなどが考えられるので、まずは解決してください。

タッチ操作のための処理を書く

冒頭で書いた通り、Bootstrap4.2以降はタッチ操作にも対応しているようなので、今更書く必要もないかもしれませんが、諸事情で4.1から移行できないなどあれば、このコードでなんとかできると思います。移行できないなんてことはないと思いますが・・・。

bootstrap.carousel-swipe.jsに下記のコードをコピペして、利用している環境に合わせてクラスなどを変更してください。

$(function(){
	//$('.carousel-inner').carousel();
	var carouselTouchpoint = [];
	$('.carousel-inner').each(function(i){
		$('.carousel-inner').eq(i).on('touchstart', touchStart);
		$('.carousel-inner').eq(i).on('touchmove' , touchMove);
		$('.carousel-inner').eq(i).on('touchend' , touchEnd);

		function touchStart(e) {
			var pos = position(e);
			$('.carousel').eq(i).carousel('pause');
			$('.carousel').eq(i).attr('data-touchpos',pos.x);
			//console.log(pos.x);
		}
		function touchMove(e) {
			var pos = position(e);
			carouselTouchpoint[i] = pos.x;
			//console.log(pos.x);

		}
		function touchEnd(e) {
			//var pos = position(e);
			if( carouselTouchpoint[i] < $('.carousel').eq(i).attr('data-touchpos') ){
				$('.carousel').eq(i).carousel('next');
			}else{
				$('.carousel').eq(i).carousel('prev');
			}
			$('.carousel').eq(i).carousel('cycle');
			console.log(pos.x);
		}
		function position(e){
			var x = e.originalEvent.touches[0].pageX;
			var y = e.originalEvent.touches[0].pageY;
			x = Math.floor(x);
			y = Math.floor(y);
			var pos = {'x':x , 'y':y};
			return pos;
		}
	});
});

ざっくりと解説

.carousel-innerはカルーセルが複数ある可能性も視野に入れて.eachにしています。
今になって見直してみると、その中にfunctionを定義してしまうのはいかがなものかとか、そもそもdata-touchposに値を保存する必要があるのかなどなど思いつつ解説を続けます。

function 関数名(e){}eとはなんぞやって話なのですが、これはイベントハンドラといってどのようなイベントが起こったかを判断するパラメータが参照できます。
詳しく知りたい方はconsole.log(e)で調べてみれば、開発ツールのコンソールに大量のパラメータが出力されると思います。

今回のケースだとjQueryのタッチイベント(touchstart、touchmove、touchend)をfunction positionで感知して、さらに.originalEventでタッチした際の座標を取得しています。
pageXが横軸の座標、pageYが縦軸の座標となっているので、取得の方法さえわかれば他にも色々と応用できそうですね。

touchstartでタッチした時点の座標(x,y)をそれぞれ取得して、カルーセルを.carousel(‘pause’)して停止させます。
その後取得した座標をdata-touchposとして保存しておきます。

次にtouchmoveでタッチした部分から指を動かした分の座標を取得します。
取得した座標はそれぞれのカルーセルごとに判別するため、carouselTouchpoint配列にindexを振り分けて保存しています。

最後にtouchendでdata-touchposとcarouselTouchpointに保存されている座標を比較して、タッチした時点より左に動かしていれば座標は小さくなるので次のスライドに進みます。
右に動かしていれば座標は大きくなるので前のスライドに戻るといった原理です。

スライド処理が終われば.carousel(‘cycle’)でオートスライドを再稼働させるようにしています。

まとめ

なんとも今更感のある記事内容ではありますが、touchイベントの感知やoriginalEventの取得はjQueryを使用するのであれば有効活用できる場面もあるのではと思います。

スマホ自体のスクロールイベントを無効にして座標の取得によって強制スクロールさせるようなページを作ったりなど、仕掛け的な部分は色々と考えられそうな気がします。

何かの制作時の参考にでもなれば幸いです。

関連記事