上下に展開・格納する縦型メニューjQueryの簡略化に成功

現在拙サイト・ブログ等で使用中の「上下に展開・格納する縦型メニューjQuery」はかなり煩雑で、今回整理して簡略化させることに成功。

縦型メニューのHTML


<ul>
 <li>
  <span id="accordion01" class="accordion">news</span>
  (ここに「+」または「−」が挿入される)
  <ul id="subNavi01" class="subNavi">
   <li><a href="#">ESZETT</a></li>
   <li><a href="#">TYPŒ</a></li>
   <li><a href="#">LETTER-PRESS</a></li>
  </ul>
 </li>
 <li>
  <span id="accordion02" class="accordion">works</span>
  (ここに「+」または「−」が挿入される)
  <ul id="subNavi02" class="subNavi">
   <li><a href="#">web design</a></li>
   <li><a href="#">web demo</a></li>
   <li><a href="#">print</a></li>
  </ul>
 </li>
 <li>
  <span id="accordion03" class="accordion">projects</span>
  (ここに「+」または「−」が挿入される)
  <ul id="subNavi03" class="subNavi">
   <li><a href="#">event calendar</a></li>
   <li><a href="#">letterpress map</a></li>
   <li><a href="#">line museum</a></li>
  </ul>
 </li>
 <li>
  <span id="accordion04" class="accordion">bibliography</span>
  (ここに「+」または「−」が挿入される)
  <ul id="subNavi04" class="subNavi">
   <li><a href="#">basic</a></li>
   <li><a href="#">typography</a></li>
   <li><a href="#">letterform</a></li>
  </ul>
 </li>
</ul>

これまでのjQuery


$(function(){
 $("#subNavi01, #subNavi02, #subNavi03, #subNavi04").hide();
 $("#accordion01, #accordion02, #accordion03, #accordion04").after("<span class='openClose'>+</span>");
 $("#accordion01").click(function(){
  $("#subNavi01:not(:animated)").animate({height: 'show'}, 500,'easeOutQuad');
  $("#accordion01").next().replaceWith("<span class='openClose'>–</span>");
  $("#subNavi01:not(:animated)").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion01").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi02").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion02").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi03").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion03").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi04").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion04").next().replaceWith("<span class='openClose'>+</span>");});
 });
 $("#accordion02").click(function(){
  $("#subNavi02:not(:animated)").animate({height: 'show'}, 500,'easeOutQuad');
  $("#accordion02").next().replaceWith("<span class='openClose'>–</span>");
  $("#subNavi02:not(:animated)").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion02").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi01").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion01").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi03").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion03").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi04").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion04").next().replaceWith("<span class='openClose'>+</span>");});
 });
 $("#accordion03").click(function(){
  $("#subNavi03:not(:animated)").animate({height: 'show'}, 500,'easeOutQuad');
  $("#accordion03").next().replaceWith("<span class='openClose'>–</span>");
  $("#subNavi03:not(:animated)").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion03").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi01").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion01").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi02").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion02").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi04").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion04").next().replaceWith("<span class='openClose'>+</span>");});
 });
 $("#accordion04").click(function(){
  $("#subNavi04:not(:animated)").animate({height: 'show'}, 500,'easeOutQuad');
  $("#accordion04").next().replaceWith("<span class='openClose'>–</span>");
  $("#subNavi04:not(:animated)").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion04").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi01").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion01").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi02").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion02").next().replaceWith("<span class='openClose'>+</span>");});
  $("#subNavi03").animate({height: 'hide'}, 500,'easeInQuad', function(){$("#accordion03").next().replaceWith("<span class='openClose'>+</span>");});
 });
});
うん、ものの見事に煩雑だね〜。ここではもう詳しく解説しないが、ただ1つだけ云えば、ID属性で各ナビごとに一々指示しているから。詳細は、拙ブログ上下に展開・格納するナビおよび縦型メニュー展開・収納時(開閉時)にメニュー横の+−表示が切替るjQueryをご覧あれ。

整理した結果


1.$(function(){
2. $(".subNavi").hide();
3. $(".accordion").after("<span class='openClose'>+</span>");
4. $(".accordion").click(function(){
5.  $(this).next().next().animate({height: 'show'}, 500,'easeOutQuad');
6.  $(this).next().replaceWith("<span class='openClose'>–</span>");
7.  $(".accordion").next().next().not(":animated").animate({height: 'hide'}, 500,'easeInQuad',↵
   function(){$(this).prev().replaceWith("<span class='openClose'>+</span>");});
8. });
9.});
あらまあスッキリ。
要は、クラス属性での指定に替えて汎用性を高めたことだね。
解説すると、
  • 2行目:subNaviクラスを持つUL要素で囲んだ箇所は最初見えないようにする。これはCSSにて「.subNavi {display:none;}」を指定した方が良い。ページロード時にsubNavi部分が1度表示されてから消えるという動作が解消されるから。
  • 3行目:accordionクラスを持つSPAN要素の後ろにSPAN要素の兄弟要素として「+」を追加する(詳細は縦型メニュー展開・収納時(開閉時)にメニュー横の+−表示が切替るjQueryをご覧あれ)。
  • 4行目:accordionクラスを持つSPAN要素の1つをクリックすると、
    • 5行目:このときの$(this)は実際にクリックしたaccordionクラスを持つSPAN要素を指し、それのnext().next()、つまり$(this)の次の次の兄弟要素であるsubNaviクラスを持つUL要素で囲んだ箇所が表示される。この時注意したいのは、クリックされたaccordionクラスを持つSPAN要素の次の兄弟要素は3行目で追加されるafter()内のSPAN要素であるということ。なのでsubNaviクラスを持つUL要素は次の次の兄弟要素となる。
    • 6行目:クリックされたaccordionクラスを持つSPAN要素の次の兄弟要素である、after()で追加したSPAN要素を「−」に置き換える。
    • 7行目:accordionクラスを持つSPAN要素の次の次の兄弟要素であるsubNaviクラスを持つUL要素で囲んだ箇所を格納する。ここで注意。セレクターが$(this)ではなく$(".accordion")なのは、クリックされたaccordionクラスだけでなく全てのaccordionクラスを対象にしているから。この縦型メニューは、どこか1箇所が展開されたら他の全てのsubNaviは格納するようにしているので。
    • 7行目:後半の関数では$(this).prev()と指示しているがこれは何を指しているか。この時の$(this)は7行目前半の$(".accordion").next().next()、つまりはsubNaviクラスを持つUL要素を指していて、それのprev()、つまりその前の兄弟要素であるafter()で追加したSPAN要素を指す。で、この内「−」に差替えられたものを「+」に変更する。
以上だが、click関数内に1度に展開・格納の指示が入っているので、この動作は展開したかと思えばすぐ格納されて結局subNaviクラス部分は表示されないのではないかと思うが、ここでのミソは、7行目にあるnot(":animated")。これをここに入れることによって、1回のクリックでクリックされたaccordionクラス内のsubNaviクラスはanimateしながら展開され、もう一度自身を含めたいずれかのaccordionクラスをクリックすると、クリックされたaccordionクラス内のsubNaviクラスはanimateしながら展開されると同時に、すでに展開しているsubNaviクラスはanimate状態ではないのでこれが7行目の指示のにより格納される、という動作になる。








コメント

よく読まれている記事

CSSボタンでテキストを天地中央に揃えるとき、なぜボタン高と行高を一緒にするのか

FullCalendarの導入からカレンダー毎の色指定まで

FacebookページのフィードURLを取得しウォールを自サイトに表示