スマートフォンなどで,連続スワイプのハンドリング方法をまとめておきます.

指が触れ始めたときのDOMや,離れた瞬間のDOMは簡単に取得できましたが,「今」指が触れているDOMを取得するのに苦戦しました.

先日行ったデザインリニューアル(YutaroTanaka.com)でも,この方法を使ってスマホのスワイプ対応をしています.

やりたいこと

「このような要素をタッチしたときに,触れたところの色を変えたい」 「ひとつひとつタップするのではなく,指でなぞった部分の色を変えたい」

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

[code language=“html” title=“HTML”] <span class="panel">1</span> <span class="panel">2</span> ・・・ <span class="panel">20</span> [/code]

【PC】mouseenter イベントをハンドリングする

$('.panel') でタッチ対象の要素を取得し,.on() で mouseenter イベントにイベントハンドラをセットします.

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

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

[code language=“javascript” title=“JavaScript”] $().ready(function () { $('.panel').on({ ‘mouseenter’: function () { var target = $(this); if (target.hasClass(‘panel’)) { target.addClass(‘green’); } } }); }); [/code]

マウスが触れた瞬間に,その要素の色が変化します.

【スマホ①】touchstart, touchend, touchmove を試すも...

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

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

そのため,スマホに指をつけたときの要素は色が変るけど,指を放さずに画面上を動かしても,target は変化しません.

[code language=“javascript” title=“JavaScript”] $().ready(function () { $('.panel').on({ ‘touchmove’: function (event) { var target = $(this); if (target.hasClass(‘panel’)) { target.addClass(‘green’); } } }); }); [/code]

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

[code language=“javascript” title=“JavaScript”] $().ready(function () { $('.panel').on({ ‘touchmove’: function (event) { var target = event.XXXXXXX; if (target.hasClass(‘panel’)) { target.addClass(‘green’); } } }); }); [/code]

【スマホ②】touchmove + position + elementFromPoint

試行錯誤した結果,

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

これで解決しました.

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

その際に,event オブジェクトで取得できる指の座標を,指定された座標上にある要素を取得できるdocument.elementFromPoint(X, Y) に渡します.

[code language=“javascript” title=“JavaScript”] $().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');
        }
    }

}); [/code]

まとめ

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

[code language=“javascript” title=“JavaScript”] $('.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');
        }
    }
});

[/code]

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