Ajaxの習作:MSDNのツリー(ぽい物)を実現する。

フェーズ1

 ツリービューのクリックにより子を展開・格納します。

子の展開は、子や孫の要素を表示するということであり、子の格納は、隠す(非表示)にするということです。
表示されているものを隠したり、またはその逆に表示されていないものを現したりする方法として、以下のパターンが考えられます。
  1. ツリー全体を書き直して、隠す部分を削り、現す部分を追加する。
  2. document.writeでそのページ全体を書き直すことにより、表示内容を変更します。
    問題は、全体を書き直してしまうので、書き直す量によっては時間がかかる点と、ツリー以外の範囲にも影響する点があります。
  3. ツリーの一部を書き直す。
  4. DOMインターフェイスのappendChild()、removeChild()により、タグの子要素を追加・削除する。
    全体を書き直すよりはスマートではあるが、表示・非表示を行うのに、いちいち要素を追加削除するのはいかがなものか。
  5. スタイルシートを使用して文字の表示・非表示を変更する。
  6. スタイルシートのdisplayにblock/noneを指定することにより範囲の表示・非表示の制御を行います。
    書き直しや要素の追加削除よりもっとスマートです。いちいち追加削除しなくてすむので速そうです。


 一番スマートな(3)の方法を試してみます。

ここの表示を「表示・非表示」ボタンで表示・非表示する


ソース
<html>
<script language="javascript">
<!--
function getElm(tName){
	var obj=null;
	if(document.all || document.getElementById) {
		if(document.all) {
			obj=document.all(tName);
		} else {
			obj=document.getElementById(tName);
		}
	} else {
		if(document.layers) {
			obj=document.layers(tName);
		}
	}
	return obj;
}

function changeDisp(tName){
	var elm=getElm(tName).style;
	elm.display = (elm.display!='block') ? 'block' : 'none';
}

//-->
</script>
<body>
<form name="testform">
<INPUT TYPE="button" Value="表示・非表示" onClick="changeDisp('test')">
</form>
→<p id="test" style="DISPLAY:block">ここの表示を「表示・非表示」ボタンで表示・非表示する</p>←
</body>
</html>

ツリーは、1階層だけでなく子の階層がある場合があります。
その場合は、上の例の要素を一歩進めて、表示・非表示用の<p>タグや<div>タグで括られた要素を入れ子にすます。そうすると、親を閉じると子の要素も見えなくなります。加えて子の要素の開閉状態は保存されたままになります。なお、当たり前ですがタグのIDをユニークにしないと動作しなくなります。
以下の例では、<div>タグの入れ子で括っています。
(本当ならば、+の部分をクリックしたら閉じるようになるとよりツリーっぽくなるのでしょうが、今回はとりあえずボタンで我慢してください)



+親
 +子1
  +孫11
   ・ひ孫111
  +孫12
   ・ひ孫121
 +子2
  +孫21
   ・ひ孫211
  +孫22
   ・ひ孫221

ボタンとツリーのところのソース
<form name="testform">
<INPUT TYPE="button" Value="親の下を表示・非表示" onClick="changeDisp('test0')"><br>
<INPUT TYPE="button" Value="子1の下を表示・非表示" onClick="changeDisp('test1')">
<INPUT TYPE="button" Value="子2の下を表示・非表示" onClick="changeDisp('test2')">
<INPUT TYPE="button" Value="孫11の下を表示・非表示" onClick="changeDisp('test11')">
<INPUT TYPE="button" Value="孫12の下を表示・非表示" onClick="changeDisp('test12')">
<INPUT TYPE="button" Value="孫21の下を表示・非表示" onClick="changeDisp('test21')">
<INPUT TYPE="button" Value="孫22の下を表示・非表示" onClick="changeDisp('test22')">
</form>
+親<br>
<div id="test0" style="display:block">
 +子1<br>
<div id="test1" style="display:block">
  +孫11<br>
<div id="test11" style="display:block">
   ・ひ孫111<br>
</div>
  +孫12<br>
<div id="test12" style="display:block">
   ・ひ孫121<br>
</div>
</div>
 +子2<br>
<div id="test2" style="display:block">
  +孫21<br>
<div id="test21" style="display:block">
   ・ひ孫211<br>
</div>
  +孫22<br>
<div id="test22" style="display:block">
   ・ひ孫221<br>
</div>
</div>
</div>

さて、ツリーを構築するのに上記の例のようにすべてHTMLに書き込んでおくのも大変なので、配列に入れて展開できるようにします。
+のところをクリックすると展開・格納します。

配列を使ったツリーの作成のソース
<script language="javascript">
<!--
function getName() { return this.Name_ }
function getURL() { return this.URL; }
function getContent() { return this.Content; }
function Content(tContentName, tURL) {
	var ContentName;
	var URL;
	this.ContentName = tContentName;
	this.URL = tURL;
	ContentName = getName;
	URL = getURL;
}
function Contents(tContentsName, tURL, objContent) {
	var ContentsName;
	var URL;
	var Content;
	this.ContentsName = tContentsName;
	this.URL = tURL;
	this.Content = objContent;

	ContentsName = getName;
	URL = getURL;
	Content = getContent;
}

listContents=new Array(3);
listContent=new Array(2);
listContent[0]=new Content("test11", "test11.html");
listContent[1]=new Content("test12", "test12.html");
listContents[0] = new Contents("Test01", "test1.html", listContent);

listContent=new Array(2);
listContent[0]=new Content("test21", "test21.html");
listContent[1]=new Content("test22", "test22.html");
listContents[1] = new Contents("Test02", "Test2.html", listContent);

listContent=new Array(2);
listContent[0]=new Content("test31", "test31.html");
listContent[1]=new Content("test32", "test32.html");
listContents[2] = new Contents("Test03", "Test3.html", listContent);

	for(i=0; listContents.length > i; i++) {
		objContents = listContents[i];
		document.write('<A onclick="javaScript:changeDisp('+ "'" , objContents.ContentsName, "')" + '" class="Brunch">');
		document.write('<span id="', objContents.ContentsName + '_', '" style="cursor:hand;">+</span>');
		document.write('</A>');
		document.write('<A href="', objContents.URL, '" target="_blank">', objContents.ContentsName, '</A><br>');
		document.write('<div id="', objContents.ContentsName, '" style="DISPLAY:none">');
		listContent = objContents.Content;
		for(j=0; listContent.length > j; j++) {
			objContent=listContent[j];
			document.write('<p class="Nowrap">');
			if(listContent.length-1 != j) {
				document.write('├');
			} else {
				document.write('└');
			}
			document.write('<A href="', objContent.URL, '" target="_blank">', objContent.ContentName, '</A></p>');
		}
		document.write('</div>');
	}
// -->
</script>

フェーズ1は以上でおしまい。次回フェーズ2ではJSONを使用します。