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

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

ただいまの
回答率

88.63%

JS アコーディングメニュー 開閉時のアイコン切り替え

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 787

crigw

score 24

前提

以下のJSでアコーディオンメニューを作成しています。また、現在地を取得してクラス名を付与しており、これによりページ読み込み時にクラス名is-mainNavKids--currentがついた場合には最初から子メニュー開いていたいためCSSで先述のクラス名にdisplay: block;を指定しています。さらに、CSSでアコーディオン閉じる時にはアイコンをに、開いた時にに設定しています。

実現したいこと

初期状態でアコーディオンが開いていると、開いてる状態でアイコンが、閉じた時にになってしまうので、初期状態で開いているアコーディオンにis-toggle-accNav--openを付与しを表示させ、閉じた時に付与を取り消し+にしたい。

クラス名の付与以外をCSSだけで完結できるのであれば、そちらの方が好ましいです。(IE11対応必須)

該当のソースコード

//Nav
$(function(){
  $('.is-toggle-accNav').each(function(){
      $(this).on('click',function(){
          $(this).toggleClass('is-toggle-accNav--open');
          $("+.mainNavKids",this).slideToggle()
          return false;
      });
  });
});

//current
$(function(){
  $('.mainNav__item__link').each(function(){
    var $href = $(this).attr('href');
    if(location.href.match($href)) {
      $(this).parent('.mainNavKids__item').addClass('current');
      $(this).parents('.mainNav__item').addClass('current');
      $(this).parents('.mainNavKids').addClass('is-mainNavKids--current');
    } else {
      $(this).parent().removeClass('current');
    }
  });
});
.is-toggle-accNav:after {
  background: #33105f;
  content: '\f067';
  display: block;
  font-family: 'Font Awesome 5 Free';
  font-weight: 900;
  line-height: 60px;
  position: absolute;
  right: 0;
  text-align: center;
  top: 0;
  width: 60px;
}
.is-toggle-accNav.is-toggle-accNav--open:after {
  content: '\f068';
}
.is-mainNavKids--current {
  display: block;
}
<nav class="collapsibleNav">
  <button type="button" class="is-collapsibleNav-openBtn"></button>
  <ul class="mainNav">
    <li class="mainNav__item">
      <a href="#" class="mainNav__item__link is-toggle-accNav">親メニュー1(クリックで開く)</a>
      <ul class="mainNavKids is-mainNavKids--current">
        <li class="mainNavKids__item"><a href="./index.html" class="mainNav__item__link">サブメニュー1</a></li>
        <li class="mainNavKids__item"><a href="#" class="mainNav__item__link">サブメニュー1</a></li>
        <li class="mainNavKids__item"><a href="#" class="mainNav__item__link">サブメニュー1</a></li>
      </ul>
    </li>
〜略〜

問題のスクショ

以下、メニュー1にis-mainNavKids--currentが付与されている状態。メニュー2のアイコン表示が正しい状態。
イメージ説明
イメージ説明

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • miyabi_takatsuk

    2020/01/27 11:19

    asuchi0819さん、ありがとうございます。
    こちらの検証不足ですね。
    失礼しました。
    再度検証していきます。

    キャンセル

  • miyabi_takatsuk

    2020/01/27 11:21

    crigwさん >
    大変失礼しました。
    slimバージョンを読み込んでいるのが原因でした。
    どうやら、メソッドもかなり削減されてしまうようですね。
    こちらも勉強になりました。

    キャンセル

  • crigw

    2020/01/27 15:56

    asuchi0819さん、miyabi_takatsukさん
    SlideToggleについて、いろいろご確認や検証いただきありがとうございました。

    キャンセル

回答 3

+4

あきらかな間違いは下記ですね。

(this).toggleClass('.is-toggle-accNav--open');

ドット(.)が余分です。

(this).toggleClass('is-toggle-accNav--open');

とりあえず上記を修正して希望の動作になるか確認してみてください。

追記

あと、初期状態で、カレントなら開いた状態、それ以外は閉じた状態にしておきたいのなら、CSSで設定しておきましょう。

.mainNavKids {
  display: none;
}
.is-mainNavKids--current {
  display: block;  
}

サンプルを作成したのでリンク置いておきます。

カレント開閉の処理で、カレントの時の処理で、親メニュー要素に is-toggle-accNav--openクラスを付与するコードが必要に思います。

DOMツリー構造をみて、辿っていけばいいでしょう。

子メニューがカレントの場合は、祖先の.mainNavKids の一つ前の要素にis-toggle-accNav--openクラスを付与すればいいので、下記のような感じで。
$(this).parents('.mainNavKids').prev().addClass('is-toggle-accNav--open');

親メニューがカレントの場合は、別途コードが必要になりますが、それはご自分で考えてみてください。

//Nav
$(function(){
  $('.is-toggle-accNav').each(function(){
      $(this).on('click',function(){
          $(this).toggleClass('is-toggle-accNav--open');
          $("+.mainNavKids",this).slideToggle()
          return false;
      });
  });
});

//current
$(function(){
  $('.mainNav__item__link').each(function(){
    var $href = $(this).attr('href');
    if($href === 'https://teratail.com') {
      $(this).parent('.mainNavKids__item').addClass('current');
      $(this).parents('.mainNav__item').addClass('current');
      $(this).parents('.mainNavKids').addClass('is-mainNavKids--current');
      $(this).parents('.mainNavKids').prev().addClass('is-toggle-accNav--open');
    } else {
      $(this).parent().removeClass('current');
    }
  });
});

動作確認用サンプル

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/01/27 15:54

    ご指摘いただきました内容はすでに修正済みとなっております。
    また今回の質問は`開閉時のアイコン切り替えについて`でして、カレント開閉の動作はすでに対応済みです…ですがご配慮頂きありがとうございました。

    キャンセル

  • 2020/01/27 17:16

    カレント開閉の処理で、カレントの時の処理で、親メニュー要素に is-toggle-accNav--openクラスを付与するコードが必要に思います。

    キャンセル

  • 2020/01/27 17:24

    その記述方がわからずにいるためにこちらの質問を建てた次第です。

    キャンセル

  • 2020/01/27 18:46

    DOMツリー構造をみて、辿っていけばいいでしょう。
    子メニューがカレントの場合は、祖先の.mainNavKids の一つ前で、下記のような感じで。
    $(this).parents('.mainNavKids').prev().addClass('is-toggle-accNav--open');
    他にも辿り方はありますので一例です。

    キャンセル

+1

メニューの表示条件は@crigwさんの判定したいものに読み替えてください。
面倒なのでindexを判定していますので、無視してください。

親メニューのチェックと子メニューのチェックを分離すれば、'is-toggle-accNav--open'を付けるDOMツリー見えてくると思います。

$(function(){
  $('.is-toggle-accNav').each(function(){
      $(this).on('click',function(){
          $(this).toggleClass('is-toggle-accNav--open');
          $("+.mainNavKids",this).slideToggle()
          return false;
      });
  });
  // 親メニューの条件判定
  $('.mainNav__item__link'+'.is-toggle-accNav').each(function(index) {
    $("+.mainNavKids",this).hide(); // 一旦子メニューはすべて閉じる
    if (index == 2) {//<=ここの条件式はお好きなように
        // 初期表示open
        $("+.mainNavKids",this).show();
      $(this).addClass('is-toggle-accNav--open');
    }
  });
  // 親メニューがすべて閉じていた場合は、子メニューのチェックをする
  if ($('.mainNav__item__link'+'.is-toggle-accNav'+'.is-toggle-accNav--open').length < 1) {
    $('ul.mainNavKids .mainNav__item__link').each(function(index) {
      if (index == 0) {//<=ここの条件式はお好きなように
        // 初期表示open
        $(this).parents('li.mainNav__item').find('ul.mainNavKids').show();
        $(this).parents('li.mainNav__item').find('a.mainNav__item__link'+'is-toggle-accNav')
            .addClass('is-toggle-accNav--open');
      }
    });
   }
});

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

check解決した方法

0

結果的に以下1行の追加で希望していた動きになりました。
お二人ともありがとうございました。

//current
$(function(){
  $('a.mainNav__item__link, a.mainNavKids__item__link').each(function(){
    var $href = $(this).attr('href');
    if(location.href.match($href)) {
      $(this).addClass('current');
      $(this).parents('.mainNav__item').addClass('current');
      $(this).parents('.mainNavKids').addClass('current');
      $(this).parents('.mainNavKids').prev().addClass('is-toggle-accNav--open'); //この行の追加
    } else {
      $(this).parent().removeClass('current');
    }
  });
});

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

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