Svelteアプリでクリックイベントのスマホ対応〜preventDefaultでタッチイベントを適切にさばく
※ 当ページには【広告/PR】を含む場合があります。
2023/02/21

フルHTMLによるアプリ開発のメリットは、ブラウザからであればどのようなデバイスからでも等しく同じ動作をするアプリを提供できることです。
デバイスとは言っても、大きく分けて「デスクトップ型」と「スマホ型」に区分できます。
当然この2つはハードウェアスペックの違いがあるのは仕方ないとして、大きく違うのが
HTMLでブラウザゲームを作る場合、このインターフェースによる入力の差異を意識してソースコードを実装しなくてはいけなくなります。
今回は、SvelteでHTMLアプリを作るときに知っておきたい、クリックイベントのスマホ対応術を解説していきます。
この記事で目的としてかかげるポイントは以下の通りです。
1. タッチイベントのデフォルト抑制(preventDefault)を理解する
2. 古いブラウザへのタッチイベント対応を考える
3. Svelteの{#if}構文で要素を柔軟に切り替えてイベントハンドリングする
touch系イベントをpreventDefaultする
主にタッチパネルデバイスが検知されたモバイルモードのときにブラウザが自動でタッチイベントを有効化してくれます。
タッチイベントを使うときに問題になるのが、スマホなどのタッチパネル対応デバイスで、
ブラウザからするとクリックと画面タッチの区別ができないので、最悪同じイベントを同時に2回発生させてしまいます。
クリックイベントとはそもそもマウス操作を想定したイベントですので、モバイルのときにクリックイベントが発生されても困ります。
そこで、ブラウザがモバイルモードのときにタッチイベントを適切に取り扱えるように、
イベントごとにpreventDefaultは異なるのですが、タッチイベントのデフォルト抑制とは主に下の2つになります。
1. タッチイベント処理を続けないようにする
2. クリックイベント(マウス)の伝達を抑止する
現状ほとんどのブラウザがタッチイベントのpreventDefaultに対応しているので、スマホへのクリックイベント対応がこれだけで済むようになっています。
この点を踏まえて、Svelteコードへタッチイベントを仕込んでみましょう。
Svelteへの対応はとてもシンプルで、
mousedown
mouseup
touchstart
touchend
...
<button class="position-top btn cross-key-btn"
on:mousedown={() => cursorHandler(1,0)}
on:mouseup={() => cursorHandler(1,1)}
on:touchstart|preventDefault={() => cursorHandler(1,0)}
on:touchend|preventDefault={() => cursorHandler(1,1)}><span class="top-mark">▲</span>
</button>
...
やっていることは
on:mousedown
on:touchstart|preventDefault
on:mouseup
on:touchend|preventDefault
これだけでクリックイベントのスマホ対応は完了です。
preventDefalut
古いブラウザへのタッチイベント対応
現状ではほとんどのブラウザで対応していると予測しますが、古いAndroidデバイスなどのブラウザではタッチイベントの
preventDefault
そこで、クリックイベントとタッチイベントを適切なデバイスごとに切り替えるための実装を自前で対処します。
やることは先程の
preventDefault
まずSvelteの場合、タッチイベントがブラウザで有効かどうかを任意のコンポーネントのスクリプト部でチェックすることができます。
<script lang="ts">
import { onMount } from 'svelte';
onMount(() => {
let isMobile = "ontouchstart" in window;
if (isMobile) {
console.log('タッチイベントが使えます');
} else {
console.log('タッチイベントが使えません');
}
});
</script>
...
この
isMobile
function onClick() {
if (!isMoble) {
//何らかのイベント処理
hoge();
}
}
function onTouch() {
//何らかのイベント処理
hoge();
}
もちろん古いブラウザまでサポートするかどうかは、開発者の判断におまかせします。
Svelteでデバイス対応を細かく切り分けるときのベストプラクティス
先程取り上げたスマホ対応の実装をもう一度良く眺めてみましょう。
...
<button class="position-top btn cross-key-btn"
on:mousedown={() => cursorHandler(1,0)}
on:mouseup={() => cursorHandler(1,1)}
on:touchstart|preventDefault={() => cursorHandler(1,0)}
on:touchend|preventDefault={() => cursorHandler(1,1)}><span class="top-mark">▲</span>
</button>
...
このイベントを一つの要素に詰め込んだ書式をみて、パッと「デスクトップ」と「スマホ」の両方いっぺんに対処する、と他の人から理解するのは少しむずかしいはずです。
つまり、一つの要素に多すぎるイベントを追加することがあまりいい書き方になっていません。
ではSvelteの場合どうするのが良いかというと、
{#if}〜
先程の例で置き換えると、
{#if isMobile}
<!-- モバイルモードの場合にはこっち -->
<button class="position-top btn cross-key-btn"
on:touchstart|preventDefault={() => cursorHandler(1,0)}
on:touchend|preventDefault={() => cursorHandler(1,1)}><span class="top-mark">▲</span></button>
{:else}
<!-- 通常のデスクトップモード -->
<button class="position-top btn cross-key-btn"
on:mousedown={() => cursorHandler(1,0);}
on:mouseup={() => cursorHandler(1,1);}>▲</span></button>
{/if}
のようになります。
Svelteで開発する場合、こちらの方がイベントの身通しがよくなります。
まとめ
以上、今回の記事の話をまとめると、以下のようなになります。
1. タッチイベントのデフォルト抑制(preventDefault)を理解する
2. 古いブラウザへのタッチイベント対応を考える
3. Svelteの{#if}構文で要素を柔軟に切り替えてイベントハンドリングする
一昔と比べて、スマホのブラウザもモダンなWeb APIの機能に対応してはきました。
しかし依然として細やかな操作を実現したいなら、デバイス向けの専用アプリを作るほうに一日の長がある感は否めません。
専用アプリには専用アプリの、ブラウザアプリにはブラウザアプリの良さ・悪さがありますので、開発の選択肢も複数持たれておくと良いと思います。