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

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

ただいまの
回答率

90.04%

SPレイアウトの時だけアコーディオン機能を実行したい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 4,207

aKusano

score 3635

やりたいこと

タイトルのとおりです。
レスポンシブサイトにおいて、639px以下のSPレイアウト時のみ、
通常のコンテンツをアコーディオン開閉式UIに変更するようにしたい。

現状のソースコード

<div class="js-accordion">
  <div class="js-acrTitle sp">【アコーディオンタイトル:ボタン機能】</div>
  <div class="js-acrBody">
   【アコーディオンの中身】
  </div><!-- /.js-acrBody -->
</div><!-- /.js-accordion -->
.sp {display:none;}
@media screen and (max-width: 639px){
  .sp {display:block;}
  .js-acrBody {display:none;}
}
$(function(){
  accrdion();
});

function accordion() {
    var accordionOffset = [];
    var $accordion = $(".js-accordion");


    var Accordion = {
        getaccordionOffset: function () {
            $accordion.each(function (i) {
                accordionOffset[i] = $(this).offset().top;
            });
        },
        hdlClick: function (Selector) {
            var num = $(".js-acrTitle").index(Selector);
            $("body,html").stop().animate({"scrollTop": accordionOffset[num] - 50}, 400, function () {
                Accordion.getaccordionOffset();
            });
            if (Selector.hasClass("op")) {
                Selector.removeClass("op");
                Selector.next().stop().slideUp(400, function () {
                    Accordion.getaccordionOffset();
                });
            } else {
                Selector.next().stop().slideDown(400, function () {
                    Accordion.getaccordionOffset();
                });
                Selector.addClass("op");
            }
        }
    }

    Accordion.getaccordionOffset();
    $(".js-acrTitle")
        .on("click",function () {
        Accordion.hdlClick($(this));
    });
}

問題となっているところ

アコーディオンを開閉するタイトル部.js-acrTitleは、もともとPCレイアウト時は不要で、
SPレイアウト時だけ表示すればよかったので、最初は上記コードでうまく行っていました。
(PCレイアウト時にはそもそもトリガーとなる要素が無いので機能しない)
ところが、別のページでPCレイアウト時には開閉トリガー機能の無い見出しとして.js-acrTitleを表示し、
639px以下になったところでアコーディオンになるようにする、という変則バージョンのモジュールが出てきてしまいました。
上記スクリプトでは.js-acrTitleをクリックしたら開閉してしまうので、なんとかしてアコーディオン機能を639px以下の時だけに限定しようとしてif文を書いてみたりもしたのですが、うまくいきませんでした。

実現したい仕様

1.PCレイアウト時にはただのコンテンツ
2.SPレイアウト時(639px以下)の時はアコーディオン機能
3.PCブラウザでブレイクポイントをまたぐ形で画面幅を変更した際にもアコーディオン機能の実行/停止が正しく判定されるようにする
4.SPでアコーディオン操作で.js-acrBodyを閉じた状態でPCレイアウトに変更した際も、表示状態を全てリセットして元に戻す
5.リサイズ時の判定・実行は、リサイズイベントが完了した時に1度だけ行われるように処理する(iPhoneのスクロール対策)

うまくいかなくて消してしまったので実際のコードを掲載できないのですが、上記仕様の内、1,2,4,5は実現できていました。
ただ、3の時にPC(アコーディオン無し)→SP(アコーディオン実行)は実現できましたが、一旦SPでアコーディオン機能を実行した後、ふたたびPCレイアウトに戻った時にアコーディオン機能を停止することがどうしてもできませんでした。

教えてほしいこと

基本的にクリックしたタイミングとか、リサイズしたタイミングで画面幅$(window).width()を取得して、if文で条件分岐、ということをやっていたのですが、やりたい機能全体を通した場合のロジックがうまく作れないので、
どのタイミングで何を取得し、どう判定して何を実行したら良いのか というロジック部分を中心にご教授いただけますと大変助かります。
また、もし画面幅の取得で分岐する以外のもっとスマートな実装方法があるのだとしたら、知りたいです。
(※PC用の見出しとSP用の見出しを重複記述して表示/非表示切り替える手法はNGです)

長々と申し訳ありませんが、どなたかアドバイスいただけますと助かります。
よろしくお願い申し上げます。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+3

リサイズ時に取得しておいて、クリック時に判断すれば良いと思います。また、私は画面幅で切り替えればよいと思います。特に画面幅に合わせたデザインにしているのであれば、デザインの切り替わりと機能の切り替わりは同じタイミングでよいと思います。

var sp_flag = false;
// リサイズ時に取得しておいて、
$( window ).on( 'load resize', function() {
    sp_flag = ( window.matchMedia( '(max-width:639px)' ).matches ); // IE10+
} );
$( '.js-acrTitle' ).on( 'click', function() {
    // クリック時に判断すれば良いと思います。
    if ( sp_flag ) {
        Accordion.hdlClick( $( this ) );
    }
} );

【Media Queries(メディアクエリ)とJavaScriptの連携について - Qiita】
http://qiita.com/r_abe01/items/a3a2e94b5162d949037b

【window.matchMedia - Web API インターフェイス | MDN】
https://developer.mozilla.org/ja/docs/Web/API/Window/matchMedia

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/08/08 01:34

    ご回答有り難うございます。
    まだ試せていないのですが、確認次第ご報告させていただきたいと思います。
    window.matchMedia()というのは初めて見ました。
    参考サイトの方も情報ありがとうございます。参考にさせていただきます。

    が、うっかりしていましたがこの案件、IE9が対象に入っていたりします。。
    window.matchMediaはIE10+でないと効かないんですよね?
    IE9も対象とした場合はUA分岐して別の方法で対処、でしょうか?

    キャンセル

  • 2016/08/08 01:43

    var w = window.innerWidth ? window.innerWidth : $( window ).width();
    sp_flag = ( w <= 639 );

    普通に画面幅を取る、でいいと思います。両方使う( matchMedia を基本に、無ければ幅で)という手段もありますね。

    if ( window.matchMedia ) {
    sp_flag = ( window.matchMedia( '(max-width:639px)' ).matches ); // IE10+
    } else {
    var w = window.innerWidth ? window.innerWidth : $( window ).width();
    sp_flag = ( w <= 639 );
    }

    キャンセル

  • 2016/08/08 01:48

    なるほど。ちょっとやってみますね。
    いつもありがとうございます!

    キャンセル

  • 2016/08/09 20:32

    ご報告遅くなりまして申し訳ありません。
    教えていただいたロジックで組んでみたところ、無事実現したい仕様を実装することができました!
    正直まだどうしてこのロジックならうまくいくのかちゃんと理解はできていないのですが、
    この後じっくり考えてみたいと思います。

    取り急ぎ御礼とご報告まで。
    ありがとうございました!

    キャンセル

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

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