Index

HOME > プログラムTOP > JavaScript



メニュー三態(2) : ツリービューメニュー

 JavaScriptの実用的なTIPS集です。ここでは、JavaScriptでの使用を前提としたメニューのうち、折りたたみ式のメニューを考えていきます。この形式では、メニュー項目は、ユーザーのクリックにより、子要素の表示/非表示が切り替えられます。なお、このページのサンプルは、DOM使用環境(IE5以上/NN6以上)で動作します。
PageSectionContent
(1)ドロップダウンメニュー ボタンで移動 : プッシュボタンでページを移動させる
選択時に移動 : メニュー選択時にページを移動させる
選択時に移動・改良篇 : メニュー選択時に移動の別バージョン
(2)ツリービューメニュー テキストツリー : テキストのみのツリービューメニュー
アイコンツリー/読込型 : アイコンを読み込んで加えたツリービュー
アイコンツリー/据置型 : 設置済みアイコンを利用したツリービュー
(3)ナビゲーションメニュー CSSのみのメニュー : li またはtable要素とCSSのみを使って作成
スクリプトの活用 : スクリプトを使用して作成
ブロック・メニュー : 縦に配列するナビゲーション・メニュー

sasaraan programming

Exposition

■テキストツリー

 テキストだけのツリービューのサンプルです。
// JavaScript ソース (headタグ内)

// SetNodeStyle関数 : メニュー項目の色やカーソルを設定します
// ... 引数 idParent : メニューの親項目の id
// ... 引数 strMode : 状態を示す文字列('over': mouseover時、'out': mouseout時)
function SetNodeStyle(idParent, strMode) 
{
    if (!document.getElementById) return;
    var parent = document.getElementById(idParent);
    if (strMode == "over") {
        parent.style.color = "#cc0000";
        parent.style.cursor = "pointer";
    } else if (strMode == "out") {
        parent.style.color = "#0000cc";
        parent.style.cursor = "default";
    }
}

// Node_Click関数 : 項目のclickイベントに対応して子要素の折畳み状態を設定します
// ... 引数 idChild : 子要素の id
function Node_Click(idChild) 
{
    if (!document.getElementById) return;
    var child = document.getElementById(idChild);
    if (child.style.display == "none") {
        child.style.display = "block";
    } else {
        child.style.display = "none";
    }
}
<!-- HTMLソース -->

<body onload="SetNodeStyle('p1','out'), SetNodeStyle('p2','out')">
    ...
<div><span id="p1" 
        onmouseover="SetNodeStyle('p1','over')" onmouseout="SetNodeStyle('p1','out')" 
        onclick="Node_Click('c1')">MENU1</span>
</div>
<div id="c1" style="margin-left:1em">
    <a id="page1" href="page1.html">PAGE 1</a><br>
    <a id="page2" href="page2.html">PAGE 2</a>
</div>
<div><span id="p2"  
        onmouseover="SetNodeStyle('p2','over')" onmouseout="SetNodeStyle('p2','out')" 
        onclick="Node_Click('c2')">MENU2</span>
</div>
<div id="c2" style="margin-left:1em; display:none;">
    <a id="page3" href="page3.html">PAGE 3</a><br>
    <a id="page4" href="page4.html">PAGE 4</a>
</div> 
 最も簡単なテキストだけのツリービューです。HTMLでは四つのdiv要素を配置して、親項目二つ(p1とp2)と子項目用のdiv要素(c1とc2)をつくり、子項目を二つづつ追加(page1〜page4)しています。
 JavaScriptでは、まず、親項目(p1, p2)をマウスイベントに対応させるため、SetNodeStyle関数を定義しています。さらに、HTML側でマウス操作のイベントハンドラ(onmouseover, onmouseout)に結び付けています。これは単なる見栄えを良くするための処理です。ただし、このままではマウスイベントが発生するまで有効にならないので、body要素のonloadイベントで初期化を行い、ページが読み込まれたのと同時に変化をつけるようにしています。
 次いで、Node_Click関数では、親要素をクリックした時の子要素の折り畳み状態を設定させます。これは、スタイルのdisplayプロパティに'block'あるいは'none'を設定して実現しています。'display:block' は、ブロックレベルとして表示、'display:none' は、要素をないものとして表示しない時のためのものです。

■アイコンツリー/読込型

 テキストのみのツリーにアイコンを追加してメニューを作成するサンプルです。アイコンはプリロードしてから使用します。
// JavaScript ソース (headタグ内)

// アイコンのプリロード
var aImage = new Array(2);
aImage[0] = new Image();
aImage[1] = new Image();
aImage[0].src = "dir_close.gif"; // 閉じたフォルダ
aImage[1].src = "dir_open.gif";  // 開いたフォルダ

// SetNodeStyle関数 : 上記参照
function SetNodeStyle(idParent, strMode) {
    ... 
}

// Node_Click_2関数
// ... 引数 idChild : 子要素の id
// ... 引数 idIcon : アイコンを表示する img 要素の id
function Node_Click_2(idChild, idIcon) 
{
    if (!document.getElementById) return;
    var objChild = document.getElementById(idChild);
    var objIcon = document.getElementById(idIcon);
    if (objChild.style.display=="none") {
        objChild.style.display = "block";
        objIcon.src = aImage[1].src;
    } else {
        objChild.style.display = "none";
        objIcon.src = aImage[0].src;
    }
    objIcon.style.width = "16px";
    objIcon.style.height = "16px";
}
<!-- HTMLソース -->

<body onload="SetNodeStyle('p1','out'), SetNodeStyle('p2','out'), 
                    Node_Click_2('c3','ico3'), Node_Click_2('c4', 'ico4')">
    ...
<div>
    <img id="ico3" alt=''>
    <span id="p3" 
            onmouseover="SetNodeStyle('p3','over')" onmouseout="SetNodeStyle('p3','out')" 
            onclick="Node_Click_2('c3', 'ico3')">MENU1
    </span>
</div>
<div id="c3" style="margin-left:16px; display:none;">
    <img src="file_html.gif"  alt='' style="width16px; height:16px;">
    <a id="page1" href="page1.html">PAGE 1</a><br>
    <img src="file_html.gif"  alt='' style="width16px; height:16px;">
    <a id="page2" href="page2.html">PAGE 2</a>
</div>
<div>
    <img id="ico4" alt=''>
    <span id="p4"  
            onmouseover="SetNodeStyle('p4','over')" onmouseout="SetNodeStyle('p4','out')" 
            onclick="Node_Click_2('c4', 'ico4')">MENU2
    </span>
</div>
<div id="c4" style="margin-left:16px;">
    <img src="file_html.gif"  alt='' style="width16px; height:16px;">
    <a id="page3" href="page3.html">PAGE 3</a><br>
    <img src="file_html.gif"  alt='' style="width16px; height:16px;">
    <a id="page4" href="page4.html">PAGE 4</a>
</div>		
 上記の例はアイコンを使用する時の例です。イメージオブジェクト(aImage)をJavaScript側でつくっておき、クリックイベントが起こる度に画像を読み込んで表示する(Node_Click_2関数)方法です。なお、最初から画像を表示するために、body要素の onloadイベントハンドラに、c3,c4用の初期化処理を追加しています。
 この方法だとアイコンの種類を容易に増やせるメリットはありますが、画像のプリロードが効かないブラウザではパフォーマンスが低下します。次の様に、あらかじめHTML側の表示箇所に画像を置いて、表示を切り替えるだけならこの心配はありません。ただし、HTMLの記述がやや複雑になります。

■アイコンツリー/据置型

 アイコンを追加してツリーをつくるサンプルです。アイコンは、表示箇所に直接埋め込みます。この場合、一箇所に二つのイメージを置くことになります。
// JavaScript ソース (headタグ内)

// SetNodeStyle関数 : 上記参照
function SetNodeStyle(idParent, strMode) {
    ... 
}

// Node_Click_3 関数
// ... 引数 idChild : 子要素の id
// ... 引数 idClose : 閉じたフォルダ用アイコンを表示する img 要素の id
// ... 引数 idOpen : 開いたフォルダ用アイコンを表示する img 要素の id
function Node_Click_3(idChild, idClose, idOpen) 
{
    if (!document.getElementById) return;
    var objChild = document.getElementById(idChild);
    var objClose = document.getElementById(idClose);
    var objOpen = document.getElementById(idOpen);
    if (objChild.style.display=="none")  {
        objChild.style.display = "block";
        objClose.style.display = "none";
        objOpen.style.display = "inline";
    } else {
        objChild.style.display = "none";
        objClose.style.display = "inline";
        objOpen.style.display = "none";
    }
}
<!-- HTMLソース -->

<body onload="SetNodeStyle('p5','out'), SetNodeStyle('p6','out')">
    ...
<div>
    <div style="float:left">
        <img id="close5" src="dir_close.gif" alt="" style="width16px; height:16px; display:none">
        <img id="open5" src="dir_open.gif" alt="" style="width16px; height:16px;">
    </div>
    <span id="p5" 
            onmouseover="SetNodeStyle('p5','over')" onmouseout="SetNodeStyle('p5','out')" 
            onclick="Node_Click_3('c5','close5','open5')">MENU1
    </span>
</div>
<div id="c5" style="clear:all; margin-left:16px">
    <img src="file_html.gif" alt="" style="width16px; height:16px;">
    <a id="page1" href="page1.html">PAGE 1</a><br>
    <img src="file_html.gif" alt="" style="width16px; height:16px;">
    <a id="page2" href="page2.html">PAGE 2</a>
</div>
<div style="clear:all">
    <div style="float:left">
        <img id="close6" src="dir_close.gif" alt="" style="width16px; height:16px;">
        <img id="open6" src="dir_open.gif" alt="" style="width16px; height:16px; display:none">
    </div>
    <span id="p6" 
            onmouseover="SetNodeStyle('p6','over')" onmouseout="SetNodeStyle('p6','out')" 
            onclick="Node_Click_3('c6','close6','open6')">MENU2
    </span>
</div>
<div id="c6" style="clear:all; margin-left:16px; display:none">
    <img src="file_html.gif" alt="" style="width16px; height:16px;">
    <a id="page3" href="page3.html">PAGE 3</a><br>
    <img src="file_html.gif" alt="" style="width16px; height:16px;">
    <a id="page4" href="page4.html">PAGE 4</a>
</div>		
 親項目 p5, p6 の前に div 要素を追加し、中に、閉じたフォルダ(close5, close6)と開いたフォルダ(open5, open6)の二つのイメージを配置しておきます。この時、div 要素はブロックレベルなので 'float:left' を指定して回り込みを設定する必要があり、また、以降の div 要素では 'clear:all' を指定して、この回り込みを解除しなければなりません。
 二つのイメージは、このままでは両方とも表示されてしまいますので、Node_Click_3 関数で、一方を 'display:inline' を指定して表示、もう一方を 'display:none' を指定して非表示にします。

www.sasaraan.net

(c) morijoh