現在HTML,Javascript(jQuery)を使ってスマホ用Webページを作っています。
そこでおかしな現象が起こってしまい対処したいのですが、そのように対処するのがいいか検討中です。
結論から言うと、
touchstartによるイベント処理時、タップしたボタンだけでなく、そのボタンを押したことにより表示されるモーダル内のリンクも処理が実行されてしまいます。そのリンクがタップした場所に表示される場合に限ってですが。つまりタップした場所にボタンとリンクが時間差でも表示される時そのどちらもが実行されてしまいます。そのような現象の対応方法はどのようにすべきでしょうか?
コードは以下のようになっています。
var _e = ("ontouchstart" in document) ? 'touchstart':'click';
$(window).on("load resize",function(){
$(#a_btn).on({_e,function(){
// モーダルを表示する処理。hiddenになっているモーダルエリアをshowする。
})
})
結果的に次のようにすることで対処はできたのですが、いまいち綺麗な直し方とは言えないですし、動きがモッサリしてしまったり、端末によって時間のズレが生じそうだったりと懸念点は多いです。
var _e = ("ontouchend" in document) ? 'touchend':'click';
$(window).on("load resize",function(){
$(#a_btn).on({_e,function(){
setTimeout(function(){
// モーダルを表示する処理。hiddenになっているモーダルエリアをshowする。
},10);
// settimeoutを書く前は以下のような記述を入れていましたが、起動したモーダルはクリックされました。
// _e.preventDefault();
})
touchendに変更し、setTimeoutを使っています。
どうも2つ処理が実行される原因がtouchstartのイベントが維持時間がありそうなのです。
イベントが瞬間的には知らず、少し続いているような。そのためsetTimeoutで実行を遅らせることにより、2つの処理が発生するのを防ぎました。
touchendは手が離れた瞬間から計測しないと処理にばらつきが出るためです。
このような暫定的な対応は致しましたが、かなり懸念点が残ります。
このような経験がある方などアドバイス頂ける方がいらっしゃいましたらよろしくお願いいたします。
ちなみに処理の最後に
・preventDefault();
・return false;
を書いても問題は解決されませんでした。
よろしくお願い致します。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+4
質問者様がおっしゃっている現象は確かに起こります。
touchstart
イベントが発生するタイミングはGoogleのWeb Fundamentals サイト上でのタップ操作をサポートするによると初めて要素に指が触れたとき、またはユーザーがマウスでクリックをしたときに発生
と記載してあります。
なので、ボタンをクリックしてmodalが出現するUIで、modal内に設定してあるtouchstart
イベントや、リンクなどのDOMの位置がボタンと一緒になった場合、画面上ではボタンの位置をtouchしているので、イベントが発生してしまいます。
なのでこの場合は、ボタン要素にevent.preventDefault()
してあげてください。
質問者様のコードをお借りするとしたら以下の通りになると思われます。
var _e = ("ontouchstart" in document) ? 'touchstart':'click';
$(window).on("load resize",function(){
$(#a_btn).on({_e,function(event){ //(event)を追記
event.preventDefault() //ココを追記
})
})
僕のローカル環境で再現したコードも貼っておきます。
コード内容は、以下のとおりです。
- ボタンを
touchstart
したらmodalが画面全体に出る - modal自体に
touchstart
イベントにmodalを閉じるような内容を付与、
通常のtouchstart
のみではボタンのtouchstart
とmodalのtouchstart
が同時に呼ばれてしまうので、modalが開けません(詳しく言うと、ボタンのtouchstartをcallした瞬間に、modalが出て、touchstartが反応してしまって閉じる状態になる)
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#modal{
display: none;
position: absolute;
top:0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
background: rgba(0,0,0,.6);
}
#modal.is-active{display: block;}
</style>
</head>
<body>
<button id="button">modal出現</button>
<div id="modal"></div>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
$('#button').on('touchstart', function(e){
e.preventDefault()
$('#modal').addClass('is-active')
})
$('#modal').on('touchstart', function(){
$('#modal').removeClass('is-active')
})
//# sourceURL=userscript.js
</script>
</body>
</html>
繰り返しになりますが、ボタンのtouchstart
イベントにevent.preventDefault()
してあげてください。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
いまいちわからないのですが、「登録したイベントが複数回起こる」というのであれば $(window).on("load resize",function(){});
の中で $(#a_btn).on();
をしているので、ロード/リサイズのたびにイベントを重複して登録しているからです。
また、モーダルの仕様がわからないので回答しずらいです。「モーダル」が前面に配置して表示を消しているだけの場合、ボタンがあればクリックできます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.36%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/09/05 05:07
やはりこのような現象は起きるのですね。その根拠となる説明をしていただいて大変感謝しております。ただ投稿内容にも記載した通り、preventdefaultでは処理は止まりませんでした。回答者様がアドバイスしてくださってるように書きました。
なにかそうなりうる原因や対応方法など思い当たる部分がございましたらお教えいただけるとうれしいです。
2017/09/05 11:13
2017/09/06 11:56
2017/09/12 08:13
2017/09/12 10:37
2点ほど気になる点があります。
1. _e.preventDefault()はエラーなく実行されますか?
var _e = ("ontouchend" in document) ? 'touchend':'click';
と書いてありますが、_eはただのstringではないでしょうか。
preventDefault()メソッドがあるeventオブジェクトはcallback関数のargumentsに渡ってくるものです。
$(#a_btn).on({_e,function(event){ //ここのeventです
// _e.preventDefault() ではなく以下です。
event.preventDefault()
})
2. preventDefault()は一番上に追記してください。
$(#a_btn).on({_e,function(event){
//ここです
})
ちょっと試してみてください。
また、on()の中身は
on({_e, function()})であっていますか?
僕がその書き方を知らないので間違っていたら申し訳ないのですが
.on('click', function(){ })じゃなくても動きましたでしょうか?