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

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

ただいまの
回答率

88.79%

【jQuery】「レスポンシブ」Window幅を変えた場合に、リロード無しで別の動きをさせたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 5,734

umauman

score 57

前提

レスポンシブでグローバルナビゲーションを作っています。
ウィンドウの幅をドラッグして大きくしたり小さくしたりした場合に、リアルタイムでウィンドウ幅を感知して、スマートフォン、PCサイトで異なる動きをさせたく思っていますがうまくいきません。
※ウィンドウ幅感知の部分をのぞけば意図通りの動作をしています。

実現させたい仕様

■スマートフォン(767pxまで)
二階層目があり、それも開閉

- - - - - - - -
会社概要 ↓
- - - - - - - -
商品 ↓
- - - - - - - -

それぞれをクリックしたら二階層目が展開する。
矢印の向きが「↑」に変化し、クリックしたら再び閉じて「↓」になる。

- - - - - - - -
会社概要 ↑
- - - - - - - -
> 沿革
- - - - - - - -
> 地図
- - - - - - - -
商品 ↑
- - - - - - - -
> 商品A
- - - - - - - -
> 商品B
- - - - - - - -

■PCサイト(768px以上)
クリックしても二階層目は開閉させない。

| 会社概要 | 商品 |

現在の記述 ※「Window幅を感知して処理を変える」以外の部分は意図通り動作する

<ul>
    <li class="dropdown"><a href="#" class="open">会社概要</a>
        <ul>
            <li><a href="#">沿革</a></li>
            <li><a href="#">地図</a></li>
        </ul></li>
    <li class="dropdown"><a href="#" class="open">商品</a>
        <ul>
            <li><a href="#">商品A</a></li>
            <li><a href="#">商品B</a></li>
        </ul></li>
</ul>
$(window).on('load resize', function(){//window幅に変更があった場合に感知させたい(が、うまくいっていない)
    if( window.matchMedia('(max-width:767px)').matches ){//スマートフォンの場合
        $('.dropdown').on('click','> .open', function(e){
            e.preventDefault();
            $(this).next('ul')
            .slideDown('fast', function(){
                $(this).prev('.open').removeClass().addClass('close');
            })
        }).on('click','> .close', function(e){
            e.preventDefault();
            $(this).next('ul')
            .slideUp('fast', function(){
                $(this).prev('.close').removeClass().addClass('open');
            })
        });
    }else{//それ以外(PCの場合)
        $('.dropdown').children('a').next('ul').hide();
    }
});
@media only screen and (max-width: 767px) {
    .dropdown > .open::after {
        content: '↓';
    }
    .dropdown > .close::after {
        content: '↑';
    }
}
@media only screen and (min-width: 768px) {
    .dropdown ul{
        //今のところ特に何も記述はしていないが display:none !important;を入れるべき?(後述)
    }
}

上記の記述で、PC幅でリロード、スマートフォン幅でリロードした場合、それぞれ意図した動きになっています。
ただ、ウィンドウの幅をマウスをドラッグして変更した時下記の動きになります。

①最初PCウィンドウ→②スマートフォンサイズにせまくする→③再びPCウィンドウサイズにする

①、②までは意図通りの動きをします。
③になると「会社概要」や「商品」をクリックすると二階層目が展開されるようになってしまいます。

補足

そもそもウィンドウの幅を任意で変えるユーザーはいないような気もしますのでこのような処理は必要ないのかもしれませんが向学のため、なぜ条件分岐通りに動かないのか知りたく思っています。

またCSSのメディアクエリ「min-width:768px」で二階層目のメニューを「display: none !important;」で非表示にしたら良いかとも思ったのですが、

①最初PCウィンドウ→②スマートフォンサイズにせまくする→③再びPCウィンドウサイズにする
上記のステップの①で一階層目のメニューをクリックしてから②にすると二階層目が展開されない状態で矢印が上を向いてしまいます。


ウィンドウサイズを変更した場合、リロード無しでPC⇔スマートフォンでそれぞれ仕様通りの動きを反映させるにはどのように記述をするべきなのでしょうか?ご教授いただけますと助かります。どうぞよろしくお願いいたします。

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+2

質問の回答というわけでは無いですが、
レスポンシブだとフラグ管理が複雑になってしまうので、
自分の場合、極力CSSのメディアクエリでimportant指定をして、
動きを固定するようにしていますね。

例えば、スマホサイズの時サブメニューが展開される部分を、
PCサイズではimportant指定で展開されない様にします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/16 16:07

    ご回答ありがとうございます。

    先にご回答いただいた方々の方法で実現をしてみたかったのですが、スキル不足で叶わず…
    加えて、調べていくうちに、アドバイスの通り、PCサイズでは二階層目を「display:none !important」で見えないようにするのが一番良い方法なのかと思いました。補足に書いたような不具合はあるのですが、スマートフォンだとウィンドウ幅も変えられないので…

    特に今回のようなケースはWindow Resizeの囲みは削除し、単にif( window.matchMedia('(max-width:767px)').matches ){}のみ残すシンプルなもので良いのかと思いました。

    再度、ありがとうございました。

    キャンセル

+2

ざっとしか見ていませんが、(例えば)下記のような書き方をすると resize イベントが起こるたびに .open に click イベントが設定されます。

$( window ).on( 'load resize', function() {
    $( '.open' ).on( 'click', function() {} );
} ); // 説明のために簡略化

処理によりますが、matchMedia の状態をリサイズ時に保存して、クリック時にそれを確認するのが良い気がします。(クリックイベントを毎回外す事も出来ますが)

var flag = false;
$( window ).on( 'load resize', function() {
    flag = ( window.matchMedia('(max-width:767px)').matches ); // 状態を保存
} );
$( function() {
    $( '.open' ).on( 'click', function() {
        if ( flag ) {

        } else {

        }
    } );
} );

あと多分転記ミスだと思いますが、$(this).next('close') は $(this).next('.close') では?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/15 18:11

    なかなか理解が足りず本当に申し訳ございません。
    変数を使って先に記述することに意味がありそうだと思いました。

    ifとelseで同一のセレクタに対して分岐をすればうまくいくところまでわかってきたのですが、もうちょっとシンプルにして質問をし直しました。
    https://teratail.com/questions/69215

    本質問に追記すべきか悩んだのですが、若干質問内容の方向性が変わってしまったので、新しい質問にしました。
    もし差し支えなければ再び助けていただけるととてもありがたく思います。

    キャンセル

  • 2017/03/15 18:33

    > 変数を使って先に記述
    $.on( いべんと, function() {この中でイベントを登録したら「いべんと」が起こるたびに中で設定したイベントも増え続ける}); ということを言っているのですが、もう少し上手い説明が必要そうですね。お役に立てなかったようで残念です。

    > 新しい質問
    そちらの質問が解決した際にはこちらに解決方法を書き、「解決済」にしてくださいね。
    がんばってください!

    キャンセル

  • 2017/03/15 18:52

    わざわざご返信ありがとうございます。
    ご説明いただいた内容をもう少し落ち着いて理解してみるよう引き続き努力をしてみます。

    >そちらの質問が解決した際にはこちらに解決方法を書き、
    >「解決済」にしてくださいね。

    こちらもアドバイスありがとうございます。
    新しい質問へのリンクを追記欄を設けて貼って誘導したら良いのか、
    でもそれだけだと解決にはできないし…と悩んでいたので助かります!

    キャンセル

+1

こういうことでしょうか。
デモ

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/14 21:04 編集

    何度も申し訳ございません。
    キャッシュをクリアしたり、ブラウザを変更してみたりしたのですが、
    なかなか希望通りの動きになりません;

    下記のような動きになることを確認しました。

    ①最初にPCサイト幅→②スマートフォン幅→③もう一度PC幅

    ①【PC】二階層目のメニューが展開されています。
    ②【スマホ】二階層目が展開されています。クリックをしたら第二階層が開閉します(後者の部分の動きは希望通りです)
    ③【PC】二階層目のメニューが閉じるものの、クリックをしたら第二階層が開閉します。(前者の部分は希望通りです)


    ①最初にスマートフォン幅→②PCサイト幅→③もう一度スマートフォン幅

    ①【スマホ】二階層目が最初から展開されています。クリックしても第二階層が開閉しません。
    ②【PC】二階層目のメニューが閉じるものの、クリックをしたら第二階層が開閉します。(前者の部分は希望通りです)
    ③【スマホ】二階層目のメニューが展開されています。クリックしたら第二階層が開閉します(後者の部分は希望通りです)


    説明が悪いのかもしれませんが、下記のようなものを希望しております。
    PC・・・第二階層がない(ドロップダウンしない)シンプルなグローバルナビゲーションとして見せたい。
    スマートフォン・・・第二階層が開閉するグローバルナビゲーションとして見せたい。

    本当に何度もありがとうございます。(と申し訳ない気持ちです。説明が下手なのだと思います)

    キャンセル

  • 2017/03/14 21:16

    デモ更新しました。

    キャンセル

  • 2017/03/14 22:35

    再度、ご回答ありがとうございます。
    ほぼ意図する動きなのですが、スマートフォン幅で見ると二階層目のナビゲーションが最初から開いた状態になっています。

    後は…なかなか初心者にはハードルの高いソースになってきました(悲)

    CSSのメディアクエリのようにウィンドウ幅をリアルタイルに判定して、動きを変えるみたいなことは、jQuery(JavaScript)だと、もしかするとそこまで簡単にはいかなかったりするのでしょうか…

    何度もお付き合いいただいており、本当にすみません。

    キャンセル

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

  • ただいまの回答率 88.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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