スマートフォンなどで、連続スワイプのハンドリング方法をまとめる。
指が触れ始めたときのDOMや、離れた瞬間のDOMは簡単に取得できるが
「今」指が触れているDOMを取得するのに苦戦した。
先日行ったホームページのデザインリニューアルでも
この方法を使ってスマホのスワイプ対応をした。
やりたいこと
「このような要素をタッチしたときに、触れたところの色を変えたい」
「ひとつひとつタップするのではなく、指でなぞった部分の色を変えたい」
タッチ対象は、下記のような spanタグを用意して、CSSで成形する。
<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 で背景色をつけている)
$().ready(function () {
$('.panel').on({
'mouseenter': function () {
var target = $(this);
if (target.hasClass('panel')) {
target.addClass('green');
}
}
});
});
マウスが触れた瞬間に、その要素の色が変化する。
PCは余裕
(スマホ)touchstart, touchend, touchmove など → ×
touchstart, touchend, touchmove などのイベントが発生した時の要素の要素取得を試みた。
ハンドラ内の記述「var target = $(this); 」で取得できるのは、タッチした瞬間の要素。
そのため、スマホに指をつけたときの要素は色が変るけど、指を放さずに画面上を動かしても、target は変化しない。
$().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は取得できず、結果は同じ。
$().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) に渡す。
これによって、指定された座標上にある要素を取得できる
$().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でもスマートフォンでも連続タッチイベントが取得できた。
$('.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');
}
}
});
イベントをハンドルするときに、座標からアプローチするという発想がなかなか出てこなかったので、メモ。