よく記事の折りたたみのJAVASCRIPTがありますが、以下サイトのような「全てのレスの本文を表示」「全てのレスの本文を隠す」を備え、個別にも折りたたみできるようなスクリプトの具体的なソースをどなたかご教授願えませんか?あまりprototypeなどは使用したくありません。あと複数のブラウザで動作するものを望んでいます。次ページに移動したり、そのページに戻ったりしてもその状態がキープされればなお良いのですが・・・。完璧な回答の方には高ポイント差し上げます。よろしくお願いします。
http://komachi.yomiuri.co.jp/t/2010/0601/319856.htm?g=04
前回質問 http://q.hatena.ne.jp/1275454037 のコメント欄での付加情報を確認のため書き加えておきます
・ブログやCMSなどへの適用ではなく通常のページに採用するとの事
・javascriptについてはあまり判らないとの事
・状態保存は今回質問で新たに追加された仕様
ブログやCMSを使っている場合は構成要素が特定できるためプログラムしやすいのだが、通常ページとなると構成から考えなければならないという大きな問題がある
まずは、前回質問向けに説明用として作っておいたものがあるので比較して欲しい
(状態の保存についてはentryにidを付加するところまでしか行っていない。)
(1)最低限の機能に絞った例
<html> <head> <meta http-equiv="content-style-type" content="text/css"> <meta http-equiv="content-script-type" content="text/javascript"> <style> <!-- /* デフォルト非表示の場合の例 */ div.entryBody { display:none; } //--> </style> <script type="text/javascript"> <!-- function visibleControl(e1, e2) { var c = (e1.className == 'enable' ? 'block' : 'none'); // 表示か非表示かを設定 if (e2 != '') { // 特定のエントリーが指示されている場合の処理 document.getElementById(e2).style.display = c; // } else { // 指示がない場合の処理 // getElementsByClass を使うと楽なのだが、より多くのブラウザに対応させるため TagName を採用 for each(var d in document.getElementsByTagName('div')) { // すべてのdivタグをスキャン if (d.className == 'entryBody') { // 'entryBody'クラスだけを対象にする d.style.display = c; } } } } //--> </script> </head> <body> <div id="header">ヘッダー</div> <div class="menu">メニュー</div> <a href="#" class="enable" onclick="visibleControl(this, '')">▼全エントリー表示する</a> <a href="#" class="disable" onclick="visibleControl(this, '')">▲全エントリー隠す</a> <hr /> <a href="#" class="enable" onclick="visibleControl(this, 'e1')">▼エントリー1を開く</a> <a href="#" class="disable" onclick="visibleControl(this, 'e1')">▲エントリー1を隠す</a> <div id="e1" class="entryBody">エントリー1の本文だよ</div> <hr /> <a href="#" class="enable" onclick="visibleControl(this, 'e2')">▼エントリー2を開く</a> <a href="#" class="disable" onclick="visibleControl(this, 'e2')">▲エントリー2を隠す</a> <div id="e2" class="entryBody">エントリー2の本文だよ</div> <hr /> <div>その他もろもろ</div> <hr /> <div id="footer">フッター</div> </body> </html>
(2)見栄えを少しだけ整えた例
<html> <head> <meta http-equiv="content-style-type" content="text/css"> <meta http-equiv="content-script-type" content="text/javascript"> <style> <!-- /* デフォルト非表示 */ div.entryBody { display:none; } /* 今回はAタグを使ったのでボタン風にアレンジ */ a.enable, a.disable { margin:3px; padding:2px; border:2px outset #cccccc; background:#cccccc; text-decoration:none; color:#000000; } //--> </style> <script type="text/javascript"> <!-- function visibleControl(e) { // // 表示か非表示かを設定 var c = (e.className == 'disable' ? 'none': 'block'); // // 対象とする範囲の決定 var p = e.parentNode; // 親ノードを対象とする if (p.className == 'entryTitle' || p.className == 'entryBody') { // エントリー内のボタンの場合の対象範囲 p = p.parentNode; // 親の親ノードを対象とする } else { // エントリー外のボタンの場合の対象範囲 p = document.body; // ボディ全体を対象とする } // // 対象範囲内のdiv要素内をサーチして処理 for each(var d in p.getElementsByTagName('div')) { if (d.className == 'entryBody') { // 本文に対する処理 d.style.display = c; // 本文の表示/非表示切り替え } else if (d.className == 'entryTitle') { // タイトルに対する処理 for each(var a in d.getElementsByTagName('a')) { // 開くボタンを探す if (a.className == 'enable') { // 開くボタンが見つかった場合は表示/非表示を切り替える a.style.display = (e.className == 'enable' ? 'none': 'inline'); // 表示/非表示は押されたボタンによる } } } } } //--> </script> </head> <body> <div id="header">ヘッダー</div> <div class="menu">メニュー</div> <a href="#" class="enable" onclick="visibleControl(this)">全エントリー開く</a> <a href="#" class="disable" onclick="visibleControl(this)">全エントリー隠す</a> <hr /> <div id="entry1" class="entry"> <div class="entryTitle"> エントリー1のタイトルだよ <a href="#" class="enable" onclick="visibleControl(this)">▼エントリー1を開く</a> </div> <div class="entryBody"> エントリー1の本文だよ <a href="#" class="disable" onclick="visibleControl(this)">▲エントリー1を隠す</a> </div> </div> <hr /> <div id="entry2" class="entry"> <div class="entryTitle"> エントリー2のタイトルだよ <a href="#" class="enable" onclick="visibleControl(this)">▼エントリー2を開く</a> </div> <div class="entryBody"> エントリー2の本文だよ <a href="#" class="disable" onclick="visibleControl(this)">▲エントリー2を隠す</a> </div> </div> <hr /> <div>その他もろもろ</div> <hr /> <div id="footer">フッター</div> </body> </html>
上記を比較してもらえれば、見た目を整えようとしたり、汎用性を持たせようとすればするほどスクリプトもHTML自体の構成も複雑になってくることがわかると思う
どこで妥協するかが問題になるのだけれど、これ以上は、ベースとなるHTMLの部分がある程度決まってこなければ正直難しい
この先の展開としては、
・ベースとなるHTML部分について上記(1)あるいは(2)にあわせることが出来るのか?
・それとも既に、ある程度出来上がってデザインがあるならば、それを返答してスクリプトのほうをあわせるほうが多分早い
のいずれかを決めて新たな回答(タイミングによるので私が回答するとは限らない)を待ってもらうという形になる
状態保存については、その際に付加すればいい
スクリプトを書いてから言うのもおかしいけど
世の中でCMSが多く採用されている理由が、このような面倒なことを回避したいためだったりするので、オリジナリティにこだわる必要があるかどうか、考え直したほうがいいとは思う
独自スクリプトを理解するよりは、多くの人が使っていて、ある程度完成した物を使うほうが確実だしね
厳密性にこだわるならMovableType、自由度の高さならWordPressあたりを使うと情報多いよ
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>はてなサンプル</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function(){ $("#list li div:nth-child(1)").addClass("title"); $("#list li div:nth-child(2)").addClass("content"); $(".title").click(function(){ $(this).next().toggle(300); }); $("#open_all").click(function(){ $(".content").show(400); }); $("#close_all").click(function(){ $(".content").hide(400); }); }); </script> <style type="text/css"> <!-- #list { list-style-type: none; clear: both; } #list li { margin-top: 10px; } #status { float: left; } .title { background-color: #E1E1E1; } .title:hover { background-color: #CCC; } .content { background-color: #F9F9F9; } * { margin: 0px; padding: 0px; } #open_all { background-color: #FFE79B; display: block; height: auto; width: auto; float: left; cursor: default; } #close_all { background-color: #FFE79B; display: block; height: auto; width: auto; float: right; cursor: default; } #open_all:hover { background-color: #F90; } #close_all:hover { background-color: #F90; } --> </style> </head> <body> <div id="open_all">全部開く</div> <div id="close_all">全部閉じる</div> <ul id="list"> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> </ul> </body> </html>
IEとFirefoxで確認してあります。
>あまりprototypeなどは使用したくありません。
javascriptの勉強が目的なので、安易にjQueryやprototypeを使いたくないということでしょうか?
どちらにせよ、クロスブラウザに対応するために上記ライブラリと同じ機能を実装することになります。車輪の再開発はあまり勧められたものではないので、実務においては作業効率向上のためjQueryなどのライブラリを使って下さい。
勉強が目的であればソースコードリーディングがおすすめです。
ありがとうございます。
仕事から帰ってきたら詳しく見てみます。
そうですね、jQueryやprototype使うと私には全く仕組みがわからずそして覚えず仕舞いなので(^_^;;)
これ全部開く全部閉じるは両方表示されているのではなく全部開くをクリックしたら全部閉じるに変わるなんていうことも出来るんでしょうか?
答え合わせです。自分で作ったソースと比べてみると、考え方の違いが分かって面白いですよ。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>はてなサンプル</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> //変数定義 var maximum_list_size; var current_list_size; var duration = 300; var LABEL = { CLOSE:"すべて閉じる", OPEN:"すべて開く" }; //関数群定義 eはeventの頭文字 var e = { closeAll: function(){ $(".content").hide(duration); current_list_size = 0; $("#switch").html(LABEL.OPEN); }, openAll: function(){ $(".content").show(duration); current_list_size = maximum_list_size; $("#switch").html(LABEL.CLOSE); }, closeOne: function(t){ $(t).next().hide(duration); current_list_size --; if(current_list_size == 0){ $("#switch").html(LABEL.OPEN); } }, openOne: function(t){ $(t).next().show(duration); current_list_size ++; if(current_list_size == maximum_list_size){ $("#switch").html(LABEL.CLOSE); } } } //初期化処理 $(function(){ maximum_list_size = $("#list > li").size(); current_list_size = maximum_list_size; $("#list li div:nth-child(1)").addClass("title"); $("#list li div:nth-child(2)").addClass("content"); $(".title").click(function(){ if($(this).next().css("display") == "none"){ e.openOne(this); }else { e.closeOne(this); } }); $("#switch").click(function(){ if($("#switch").html() == LABEL.CLOSE){ e.closeAll(); }else { e.openAll(); } }); }); </script> <style type="text/css"> <!-- #list { list-style-type: none; clear: both; } #list li { margin-top: 10px; } .title { background-color: #E1E1E1; } .title:hover { background-color: #CCC; } .content { background-color: #F9F9F9; } * { margin: 0px; padding: 0px; } #switch { background-color: #FFE79B; display: block; height: auto; width: auto; float: left; cursor: default; } #switch:hover { background-color: #F90; } --> </style> </head> <body> <div id="switch">すべて閉じる</div> <ul id="list"> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> <li> <div>タイトル</div> <div>内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> 内容内容内容内容内容内容内容内容内容<br /> </div> </li> </ul> </body> </html>
ありがとうございます。
ブラウザで見てみたのですがなぜか動きませんでした。
仕事から帰ってきたら再度見てみます。
あと、一応状態保存の件は前回より書いていました。
ベースとなるHTML部分について上記(1)あるいは(2)にあわせること出来ます。
MovableTypeですか・・・。ふーむ・・・。