冬言響 / 日記

アメコミとか映画とか音楽とか猫とか単車とか自転車とか革とか銀とかジーンズとかブーツとか今日喰ったものとか。

RSS2.0

アコーディオンメニュー

<dl id="archive">
<dt>2013年</dt>
	<dd>1月</dd>
	<dd>2月</dd>
	(略)
	<dd>11月</dd>
	<dd>12月</dd>
<dt>2012年</dt>
	<dd>1月</dd>
	<dd>2月</dd>
	(略)
	<dd>11月</dd>
	<dd>12月</dd>
</dl>

みたいな定義リストがあって、普段は dd を非表示にしといて年号をクリックするとその年の月を表示、他の年の月は非表示、にしたい。まあどこにでもよくあるごく普通のありふれたアコーディオンメニューですな。jQuery の解説してるサイトならたいがいサンプルがある。

のだけど、そーゆーサンプルってだいたい定義リストだったら dt と dd が一対一だったり、あるいは箇条書きリストで li の中に ul が入れ子になってたりして、とにかく見出しをクリックしたときに表示/非表示すべき要素が $("+dd", this) とか $(">ul", this) みたいなセレクタで指定出来る。

今回の場合は dd で dt と兄弟要素の関係にあり、一対一でもない。クリックされた dt より後、そして次の dt より前にある dd 要素のみを対象にし、それより前や後の dd は別に扱いたい。対象となる dd の個数は常に 12 個。

これちょっと CSS のセレクタだけじゃ無理なんじゃないか。適当にクラス名でも付ければ良いか知らんけど元の HTML はなるべくいじりたくない。幸い個数は 12 個で固定なので $("+dd, ++dd, (略), +dd+dd+dd+dd+dd+dd+dd+dd+dd+dd+dd, +dd+dd+dd+dd+dd+dd+dd+dd+dd+dd+dd+dd", this) ってやってみたら一応うまく行ったけどさすがにこれは無いだろ。コードを少しでも見やすくしようとカンマのあとに改行入れたらエラーになっちゃったし。

んでまあ色々調べてみた結果、間接セレクタに jQuery の基本フィルタの :lt も交えてみたらどうにかなった様子。

// 月(dd)を非表示。
$("dl#archive > dd").hide();
// 年(dt)をクリック。
$("dl#archive > dt").click(function() {
	// 他の月を(表示状態になっているかも知れないので改めて)非表示。
	$("dl#archive > dd").hide();
	// クリックした年(dt)の月(dd)のみを表示。
	$("~dd:lt(12)", this).show();
	$(this).nextUntil("dt").show();
	});

こんな具合で。なんか後で判んなくなりそうなのでメモ。しかし dd の個数が固定じゃなかったらもうお手上げになりそうだ。なんか別の手段でループ回してなんかするとか。dd を 1 個にしちゃってその中に箇条書きリスト入れてやるとかのがラクかな。

追記。$(this).nextUntil("dt").show(); で良いのか。よっしゃ無敵だ。