JavaScript
jQuery

【スマホ対応】jQuery 連続スワイプイベントをハンドリングする方法

More than 3 years have passed since last update.

スマートフォンなどで、連続スワイプのハンドリング方法をまとめる。

指が触れ始めたときのDOMや、離れた瞬間のDOMは簡単に取得できるが

「今」指が触れているDOMを取得するのに苦戦した。

先日行ったホームページのデザインリニューアルでも

この方法を使ってスマホのスワイプ対応をした。


やりたいこと

「このような要素をタッチしたときに、触れたところの色を変えたい」

「ひとつひとつタップするのではなく、指でなぞった部分の色を変えたい」

TouchSequence.png

タッチ対象は、下記のような spanタグを用意して、CSSで成形する。


html

<span class="panel">1</span>

<span class="panel">2</span>
・・・
<span class="panel">20</span>


(PC)mouseenter イベントをハンドリングする

$(‘.panel’) でタッチ対象の要素を取得し、.on() で mouseenter イベントにイベントハンドラをセットする。

ハンドラ内では、タッチ対象が class = “panel” を持っているとき、背景色を変える。

(今回は class = “green” に対して CSS で背景色をつけている)


js

$().ready(function () {

$('.panel').on({
'mouseenter': function () {
var target = $(this);
if (target.hasClass('panel')) {
target.addClass('green');
}
}
});
});

マウスが触れた瞬間に、その要素の色が変化する。

TouchSequence-2.png

PCは余裕


(スマホ)touchstart, touchend, touchmove など → ×

touchstart, touchend, touchmove などのイベントが発生した時の要素の要素取得を試みた。

ハンドラ内の記述「var target = $(this); 」で取得できるのは、タッチした瞬間の要素。

そのため、スマホに指をつけたときの要素は色が変るけど、指を放さずに画面上を動かしても、target は変化しない。


js

$().ready(function () {

$('.panel').on({
'touchmove': function (event) {
var target = $(this);
if (target.hasClass('panel')) {
target.addClass('green');
}
}
});
});

また、event オブジェクトの持つ event.originalEvent の、changedTouches, currentTarget, target, targetTouches, touches, … などでは、指が触れているDOMは取得できず、結果は同じ。


js

$().ready(function () {

$('.panel').on({
'touchmove': function (event) {
var target = event.XXXXXXX;
if (target.hasClass('panel')) {
target.addClass('green');
}
}
});
});


(スマホ)touchmove + position + elementFromPoint → ○

試行錯誤した結果、

「touchmove イベント時のハンドラ内で、event が起こったポジションを取得し、そのポジションにある要素を取得する。」

これで解決した。

touchmove イベントは、タッチデバイスの画面を指でなぞっている間連続して発生する。

その際に、event オブジェクトで取得できる指の座標をdocument.elementFromPoint(X, Y) に渡す。

これによって、指定された座標上にある要素を取得できる


js

$().ready(function () {

$('.panel').on({
'touchmove': function (event) {
var touch = event.originalEvent.touches[0];
var target = $(document.elementFromPoint(touch.clientX, touch.clientY));

if (target.hasClass('panel')) {
target.addClass('green');
}
}
});



まとめ

最終的には下記の通り、mouseenter, touchmove イベントにそれぞれハンドラをセットすることで、PCでもスマートフォンでも連続タッチイベントが取得できた。


js

$('.panel').on({

'mouseenter': function () {
var target = $(this);
if (target.hasClass('panel')) {
target.addClass('green');
}
},
'touchmove': function (event) {
var touch = event.originalEvent.touches[0];
var target = $(document.elementFromPoint(touch.clientX, touch.clientY));

if (target.hasClass('panel')) {
target.addClass('green');
}
}
});


イベントをハンドルするときに、座標からアプローチするという発想がなかなか出てこなかったので、メモ。