【jQuery】スマホのロングタップ(長押し)イベントの実装

Webアプリなどをレスポンシブデザインで作っている時、PCではカーソルホバー、モバイルではロングタップで要素を表示させたりしたい場合があります。意外にもロングタップイベントを受け取る方法が確立されていないので、自分で実装してみました。(jQuery使ってます)

その前に

ライブラリを使った簡単な方法

 jquery-longpressというライブラリがあり、jsファイルを読み込んで、以下のようにするだけで簡単に実装できます。

html
<script type="text/javascript" src="jquery.longpress.js"></script>
js
$('#button').longpress(function() {
    // longpress callback
    alert('You just longpress-ed a button.');
});

実際に使う時はこんな感じ。

$(function () {
    $('.target').longpress(function (e) {
        // 行いたい処理
        console.log('ロングタップ!');
    },
        function () {
            // 通常タップ時
            console.log('通常タップ!');
        },
        500 // ロングタップを検知するミリ秒
    );
});

モバイルでロングタップ時にポップアップメニューなどが出てしまう場合は、

js
// 長押し時のポップアップを無効 スマホ(ios)対策
$('.target').on({
    'touchstart': function (e) {
        e.preventDefault();
    }
});

を追記。

普通にjQuery感覚で使えてとても便利。

本題

ただ、自分の場合はターゲット要素にonClickイベントを付けていて、上記ライブラリでは、PCで右クリック時も通常クリックとしてイベントが発生(回避方法はあるかも)してしまい、思い通りの実装ができなかった。別のライブラリでも似たものはあるので、良いものがあるかもしれませんが、今回は自分で書くことにしました。

タイトルの通り、スマホの時だけ動作するスクリプトです。

「各パラメーターの設定」のところを環境に合わせて書き換えれば、コピペで動作すると思います。説明は各所コメントアウトを参照してください。

js
$(function () {

    // 各パラメーターの設定
    let target = '.target'; // ターゲット要素
    let interval_time = 100; // タップ時間判定間隔(ミリ秒)
    let longtouch_time = 500; // ロングタップ(長押し)時間(ミリ秒)interval_time の倍数

    // 判定用変数
    let touched = false; // タップ判定用
    let moveded = false; // フリック、スワイプ判定用
    let touch_time = 0; // タップ時間判定用

    $(target).on({
        'touchstart': function (e) {
            e.preventDefault(); // 各イベントを無効に

            touched = true;
            touch_time = 0;

            document.interval = setInterval(function () {
                touch_time += interval_time; // タップ時間計測

                // ロングタップ判定
                if (touched && !moveded) {
                    // ◯ミリ秒経過時
                    if (touch_time === longtouch_time) {
                        // 行いたい処理
                        console.log('ロングタップ!');
                    }
                }
            }, interval_time);
        },
        'touchend': function (e) {
            e.preventDefault(); // 各イベントを無効に

            // リリース時
            if (touched && !moveded) {
                // 通常タップ判定
                if (touch_time < longtouch_time) {
                    // 行いたい処理
                    console.log('通常タップ!');
                }
                // ロングタップ後のリリース時
                if (touch_time <= longtouch_time) {
                    // 行いたい処理
                    console.log('ロングタップ終わり!');
                }
            }

            // 各パラメーターをリセット
            touched = false;
            moveded = false;
            clearInterval(document.interval);
        },
        'touchmove': function (e) {
            e.preventDefault(); // 各イベントを無効に
            moveded = true; // フリック、スワイプ時は、ロングタップ判定しないためのフラグ
        }
    });
});

PCでも長押しイベントを発火したい場合

'touchstart'のところを'mousedown touchstart'
'touchend'のところを'mouseup touchend'

とすれば、PCでも動作します。が、自分のようにターゲット要素にonClickイベントを付けている場合は、なぜかライブラリを使った場合と同じように右クリックも通常クリックとして処理してしまうんですよね。。。いろいろ回避スクリプトを組めば良いのかもしれませんが、諦めました^^

まとめ

ライブラリを使わない場合は、結構泥臭いというか地道な実装になってしまいますね。検索するとたくさんサンプルが出てきますが、使用用途によって微妙に仕様が違うので、中身を理解して自分で実装した方が思い通りのものができるかもです。