質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • JavaScript

    20860questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    8313questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

ios端末でスライドメニューの開閉の際、領域外のタップで閉じたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,415

nyamo

score 15

ios端末でスライドメニューの開閉の際、領域外のタップで閉じたいのですが、
on clickであれば問題なく動作しても、hammer.jsを使用した際のtapでは開いた瞬間に閉じてしまい困っています。

■追記
.hammer().on("tap touchstart")とすることで、領域外のタップで閉じるようになりました。ただ、tapも動作してしまうので挙動は怪しいです。
ifで"tap"と"touchstart"の振り分けをしようと思いましたが、iosではtapもtouchstartも動いてしまうので、別の事で振り分けないとダメそうです。

$("body").hammer().on("tap", function() {
$(".casemenu").slideUp();
});


上記ではPCで確認した際、chromeのみ開いた瞬間に閉じてしまいましたので、

$("body").hammer().on("tap", function(e) {
if (!$(e.target).closest('.casemenu').length) {
$(".casemenu").slideUp();
}


上記の様にしたところ、chromeでも正常に動作し、PCでは問題ありませんが、ios safariとios firefoxで確認したら、タップした瞬間に閉じられてしまいます。

ボタンをタップした時にbodyにも伝達されているのが問題だと思うのですが、iosに対応するにはどうしたらよいのでしょうか。

もしわかる方がいらっしゃいましたらお教え頂けると幸いです。
よろしくお願い致します。 

■追記
https://jsfiddle.net/nyamo/szL8jq7m/1/
クリックの場合は、ボタン>bodyの順でios以外閉じます。

$(".casebutton").on("click", function(e){
$(".casemenu").hide();
$(this).parents(".all").children(".casemenu").slideDown("fast");
return false;
});
// クリックでスライドを閉じる
$("body").on("click", function(e) {
if (!$(e.target).closest('.casemenu').length) {
$(".casemenu").slideUp("fast");
}
});


ですが、.hammer().on("tap")では、body>ボタンの順にしなければios以外閉じれないのも気になるところです。どちらも結局、iosで閉じれないので意味のない事ですが・・・。

// クリックでスライドを閉じる
$("body").hammer().on("tap", function(e) {
if (!$(e.target).closest('.casemenu').length) {
$(".casemenu").slideUp("fast");
}
});

$(".casebutton").hammer().on("tap", function(ev){
$(".casemenu").hide();
$(this).parents(".all").children(".casemenu").slideDown("fast");
return false;
});
<header>
ヘッダー
</header>
<body>
<div class="all">
<div class="case">
<button type="button" class="casebutton">選択</button>
</div>
<div class="casemenu">
<label class="caseradio"><input type="radio"/>ああああ</label>
<label class="caseradio"><input type="radio"/>いいいい</label>
<label class="caseradio"><input type="radio"/>うううう</label>
<label class="caseradio"><input type="radio"/>ええええ</label>
</div>
</div>
</body>
.casemenu {
  display: none;
  background-color: #000;
  border: 1px solid #000;
  width: 100px;
}
.caseradio {
  display: block;
  margin-bottom: 1px;
  text-align: left;
  background-color: #fff;
}
$(".casebutton").hammer().on("tap", function(){
$(".casemenu").hide();
$(this).parents(".all").children(".casemenu").slideDown();
return false;
});
$("body").hammer().on("tap", function() {
$(".casemenu").slideUp();
});
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

stopPropagation() を使えばイベント伝播を止められると思います。

$( '.casebutton' ).hammer().on( 'tap', function( e ) {
    e.stopPropagation();
    $( '.casemenu' ).hide();
    $( this ).parents( '.all' ).children( '.casemenu' ).slideDown();
    return false;
} );

【jQuery のバブリング、preventDefault() や stopPropagation() の使用例 | Tips Note by TAM】
http://www.tam-tam.co.jp/tipsnote/javascript/post5050.html

【jQuery: イベント処理を中断するには?(preventDefault/stopPropagation/stopImmediatePropagation) - Build Insider】
http://www.buildinsider.net/web/jqueryref/022


追記1:

【Event delegation and how to stopPropagation preventDefaults · hammerjs/hammer.js Wiki · GitHub】
https://github.com/hammerjs/hammer.js/wiki/Event-delegation-and-how-to-stopPropagation---preventDefaults

ev.gesture.stopPropagation()

【Prevent tap on parent element · Issue #652 · hammerjs/hammer.js · GitHub】
https://github.com/hammerjs/hammer.js/issues/652

【GitHub - josdejong/propagating-hammerjs: Extend hammer.js with event propagation】
https://github.com/josdejong/propagating-hammerjs
Fix用ライブラリだと思われます。


追記2:

書いておられるコードでは、bodyと.casebutton それぞれのイベントが割り当てられているため、tap の度に両方走っていたようです。イベントを引き受ける関数をひとつにし、それでもbody⇒.casebutton の順で発生するイベントを一旦Timeout で外す方法でFirefoxで動きました。

jQuery( function() {
    var _timeout;
    $( '.casebutton, body' ).hammer().on( 'tap', function( e ) {
        var tgt = e.currentTarget.tagName.toLowerCase();
        if ( tgt === 'body' ) {
            if ( _timeout ) { clearTimeout( _timeout ); }
            _timeout = setTimeout( 'close_menu()', 100 );
        } else {
            if ( _timeout ) { clearTimeout( _timeout ); }
            $( '.casemenu' ).hide();
            $( this ).parents( '.all' ).children( '.casemenu' ).slideDown();
        };
        return false;
    } );
    window.close_menu = function() {
        $( '.casemenu' ).slideUp();
    }
} );
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.hammerjs/2.0.0/jquery.hammer.js"></script>

追記2:

iPad では一応動きました。iOSとデスクトップではイベント伝播の順番が逆になっていたため、それを無理やり検知する方針で組めばできました。もっとスマートなコードにも出来るとは思われますが、力尽きました。

動くサンプル:https://jsfiddle.net/4rdoa7t0/9/

jQuery( function() {
    var _timeout = []
      , funcAddT = function( t ){ _timeout.push( t ); }
      , funcClearT = function(){
            _timeout.forEach( function( t ){ clearTimeout( t ); } );
            _timeout = [];
        }
      ;
    $( 'body, .casebutton, .casemenu' ).hammer().on( 'tap', function( e ) {
        var tgt = e.currentTarget.tagName.toLowerCase();
        if ( tgt === 'body' ) {
            if ( _timeout.length ) { // button が先行した場合
                funcClearT();
              // 何もしない
            } else {
                funcClearT();
                funcAddT( setTimeout( 'close_menu()', 100 ) ); // body が先行した場合
            }

        } else if ( $(e.currentTarget).hasClass('casemenu') ) {
            if ( _timeout.length ) {
                funcClearT(); // body が先行した場合
            } else {
                funcClearT();
                funcAddT( setTimeout( 'null_func()', 100 ) ); // button が先行した場合
            }
        } else {
            if ( _timeout.length ) {
                funcClearT(); // body が先行した場合
            } else {
                funcClearT();
                funcAddT( setTimeout( 'null_func()', 100 ) ); // button が先行した場合
            }
            $( '.casemenu' ).hide();
            $( this ).parents( '.all' ).children( '.casemenu' ).slideDown();
        };
        return false;
    } );
    window.close_menu = function() {
        $( '.casemenu' ).slideUp();
        funcClearT();
    }
    window.null_func = function() {
        funcClearT();
    }
} );

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/08 18:58

    回答ありがとうございます。
    e.stopPropagation();では無理で、その変わりにif (!$(event.target).closest('#target').length)を使用している次第です。

    キャンセル

  • 2016/06/09 00:02

    誤:function() {
    正:function( e ) {
    少し書き間違えていたので回答を修正します。
    e.stopPropagation(); が効かない事例とフィックス用ライブラリを見つけたので追記します。

    キャンセル

  • 2016/06/09 03:10

    ev.gesture.stopPropagation()とpropagating-hammerjsの両方を試してみましたが、やはりiosのみ直ぐに閉じてしまいます。もしくは、領域外のタップやクリックで閉じられなくなります。
    .casebuttonのボタンを押したら、bodyも押されてしまっているので、stopPropagation()で停止させてやるのは間違いないのですが、なぜかiosではダメみたいです。

    キャンセル

  • 2016/06/09 03:59

    コードを追記しました。

    キャンセル

  • 2016/06/09 04:08

    回答ありがとうございます。
    https://jsfiddle.net/nyamo/szL8jq7m/5/
    やはり、PCブラウザでは問題ないのですが、ios端末で閲覧すると直ぐに閉じてしまいます。

    キャンセル

  • 2016/06/09 19:06

    さらにコードを追記しました。

    キャンセル

  • 2016/06/09 22:41 編集

    回答ありがとうございます。こちらで問題なく動きました。
    tap touchstartとUAの振り分けでやり直していましたが、こちらの方が安定した動作をするので使わせていただきます。というか、iOSとデスクトップではイベント伝播の順番が逆なんですね・・・。
    ご協力ありがとうございました。

    キャンセル

0

こんな処理ではどうでしょうか?
関数化すれば同じケースで利用できます。

var $el = $('#hoge'),//メニュー
    closeMenu = function(){
        //閉じる処理
    };

$(document).click(function(e){
    if(!$.contains($el[0], e.target)){
        closeMenu();
    }
});

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/08 19:05 編集

    回答ありがとうございます。
    こちらの処理ですが、.on( 'click', function()であれば問題なく動作するのですが、.hammer().on("tap", function()にすると、やはり開いた瞬間に閉じてしまいます。

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    20860questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    8313questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。