可以直接使用的树结构菜单JScript代码
我们在许多网站都可以看到窗口左边类似资源管理器的树结构菜单,
奥索站点也介绍过这种代码的JScript写法,在此我提供目前我使用
可以直接使用的代码,并详细介绍如何调用,代码也给以一定的注释。

代码包含在两个文件my_functions.js和my_treemenu.js中,在下面我将
直接将这两个文件的代码显示出来并加以说明,所必需的gif图片,
目前请到ycj_sqq.qzone.com下载(同时包含my_functions.js,my_treemenu.js)。

使用很简单,如下代码:
...
<SCRIPT src="my_treemenu.js"></SCRIPT>
<SCRIPT src="my_functions.js"></SCRIPT>
<!--初始树结构菜单 -->
<SCRIPT>
foldersTree = gFld('<FONT COLOR=#FF00FF><B>系统数据维护</B></FONT>|ftv2Root', '')
aux2 = insFld(foldersTree, gFld("<FONT COLOR=#006043><B>基础数据维护</B></FONT>", ""))
insDoc(aux2, gLnk(2, "区域数据维护", "index-sysdata_files/manager-area.php"))
insDoc(aux2, gLnk(2, "部门数据维护", "index-sysdata_files/manager-area.php"))
insDoc(aux2, gLnk(2, "人员数据维护", "index-sysdata_files/manager-area.php"))
aux2 = insFld(foldersTree, gFld("<FONT COLOR=#006043><B>商品客户维护</B></FONT>", ""))
insDoc(aux2, gLnk(2, "商品数据维护", "index-sysdata_files/manager-area.php"))
insDoc(aux2, gLnk(2, "客户数据维护", "index-sysdata_files/manager-area.php"))

</SCRIPT>
<!-- 执行构造操作 -->
<SCRIPT>
initializeDocument()
</SCRIPT>
.....

从上面代码可知,仅仅需要三步:
1,包含js文件
<SCRIPT src="my_treemenu.js"></SCRIPT>
<SCRIPT src="my_functions.js"></SCRIPT>
2,初始初始树结构菜单
调用gFld(...)生成根(Tree Root)
调用insFld(...)生成条目夹(文件夹Folder)
调用insDoc(...)生成具体条目项(菜单项ITEM)
3,执行构造操作
initializeDocument()
OK,搞定。

三个函数gFld(...)、insFld(...),insDoc(...)参数说明:
gFld()
是用初始一个Folder类,生成树根时必需调用该函数。
具体调用:
gFld(description, hreference) 返回一个Folder对象

description:
条目描述,包含条目名称,Folder类型,收缩时图标、
展开时图标。以|分隔,如
'系统数据维护|ftv2Root|ftv2RootFolder.gif|ftv2RootFolderOpen.gif'
条目名称为:系统数据维护
Folder类型:ftv2Root,目前没有太大的用处。
收缩时图标:ftv2RootFolder.gif
展开时图标:ftv2RootFolderOpen.gif

hreference:
链接对象,如果该项为空,则当点击条目时起展开或收缩作用。

insFld()
在父Folder下插入一个子Folder
insFld(parentFolder, childFolder)

parentFolder:
调用gFld()生成的父Folder对象

childFolder:
插在parentFolder下的调用gFld()生成的Folder对象


insDoc()
在父Folder下插入一个子条目项(item对象)
parentFolder:
父Folder

document:
调用gLnk()生成的item对象

gLnk说明:
gLnk(target, description, linkData)

target:目标框架
0:_top,整页
1:_blank,新打开一个窗口
2:content,当然你得命名一个框架为content了或改写代码。

description:
条目描述:
以^来分隔名称和图标

linkData:
链接对象

以下是两个文件代码:
这是我从JRUN站点查看HTML源码获取并修改而来
基本上不存在什么权利问题,你也可以修改以下代码自己随意使用

my_functions.js 代码:

var IE = (document.all) ? 1 : 0;
var NS = (document.layers) ? 1 : 0;

// WINDOW STATUS FUNCTIONS
window.defaultStatus = "";
function winStatus( msg )
{
window.status = msg;
}

function goThere( node,loc ) {
//Only perform folder opening, don't close anything
if( parent.nav.indexOfEntries[node].isOpen == false )
parent.nav.clickOnNode(node);
window.location = loc;
}

function closeMe() {
//self.close();
parent.close();
}

function formSubmit() {
parent.frames[0].document.forms[0].submit();
}

function openerReload() {
if( parent.opener.name != null )
parent.opener.location.reload();
}

function r() {
self.setTimeout("rl()", 2000);
}
function rl(){
self.location.reload();
}


// NAV TREE FUNCTIONS
function navRefresh() {
top.nav.location.reload();
}

// STRING FUNCTIONS
function trim( str ) {
// Immediately return if no trimming is needed
if( (str.charAt(0) != ' ') && (str.charAt(str.length-1) != ' ') ) { return str; }
// Trim leading spaces
while( str.charAt(0) == ' ' ) {
str = '' + str.substring(1,str.length);
}
// Trim trailing spaces
while( str.charAt(str.length-1) == ' ' ) {
str = '' + str.substring(0,str.length-1);
}

return str;
}

function strReplace( entry, bad, good ) {
temp = "" + entry; // temporary holder
while( temp.indexOf(bad) > -1 ) {
pos= temp.indexOf( bad );
temp = "" + ( temp.substring(0, pos) + good +
temp.substring( (pos + bad.length), temp.length) );
}
return temp;
}

//add by YCJ
//Remove html Language mark such as "<" and ">"
function strRemoveHtml(strIn){
if (strIn == null ) return "";
temp = strIn ;
find1 = temp.indexOf("<") ;
while(find1 > -1){
find2 = temp.indexOf(">",find1 + 1);
if (find2 == -1) find2 = find1 ;
find2 = find2 + 1 ;
temp = temp.substring(0, find1) + temp.substring(find2,temp.length);
find1 = temp.indexOf("<") ;
}
return temp;
}


my_treemenu.js代码:

//this function base from JRUN
//modify by YCJ(叶春剑)
//所有以ftv2开头的gif图片必需在 images/ 路径下(13个图片)


function Folder(folderDescription, hreference) //constructor
{
 //constant data
 descTemp_arr = folderDescription .split("|");
 this.desc=descTemp_arr[0] ;//strRemoveHtml(descTemp_arr[0]);
 // 获取节点类型,Modify by YCJ
 if( descTemp_arr[1] == null ) {
this.folderType = "ftv2Gen"; //default type is iGen
 } else {
this.folderType = descTemp_arr[1];
 }
//Assign folder default icon,Modify by YCJ
 if( descTemp_arr[2] == null ) {
this.iconSrc = "images/" + this.folderType + "Folder.gif"  ;
 } else {
this.iconSrc = descTemp_arr[2];
 }
  //Assign folder open icon,modify by YCJ
 if( descTemp_arr[3] == null ) {
  Temp_arr1 = this.iconSrc .split(".");
this.iconSrcOpen = Temp_arr1[0] + "Open.gif" ;
 } else {
this.iconSrcOpen = descTemp_arr[3];
 }
 //this.desc = folderDescription
 this.hreference = hreference
 this.id = -1 
 this.navObj = 0 
 this.iconImg = 0 
 this.nodeImg = 0 
 this.isLastNode = 0

 //dynamic data
 this.isOpen = true
 this.children = new Array
 this.nChildren = 0

 //methods
 this.initialize = initializeFolder
 this.setState = setStateFolder
 this.addChild = addChild
 this.createIndex = createEntryIndex
 this.hide = hideFolder
 this.display = display
 this.renderOb = drawFolder
 this.totalHeight = totalHeight
 this.subEntries = folderSubEntries
 this.outputLink = outputFolderLink
}

function setStateFolder(isOpen)
{

 var subEntries
 var totalHeight
 var fIt = 0
 var i=0

 if (isOpen == this.isOpen)
  return

 if (browserVersion == 2) 
 {
  totalHeight = 0
  for (i=0; i < this.nChildren; i++)
   totalHeight = totalHeight + this.children[i].navObj.clip.height
   subEntries = this.subEntries()
  if (this.isOpen)
   totalHeight = 0 - totalHeight
  for (fIt = this.id + subEntries + 1; fIt < nEntries; fIt++)
   indexOfEntries[fIt].navObj.moveBy(0, totalHeight)
 } 
 this.isOpen = isOpen
 propagateChangesInState(this)
}

function propagateChangesInState(folder)
{
 var i=0

 if (folder.isOpen)
 {
  if (folder.nodeImg)
   if (folder.isLastNode)
    folder.nodeImg.src = "images/ftv2mlastnode.gif"
   else
 folder.nodeImg.src = "images/ftv2mnode.gif"
  folder.iconImg.src = folder.iconSrcOpen
  for (i=0; i<folder.nChildren; i++)
   folder.children[i].display()
 }
 else
 {
  if (folder.nodeImg)
   if (folder.isLastNode)
    folder.nodeImg.src = "images/ftv2plastnode.gif"
   else
 folder.nodeImg.src = "images/ftv2pnode.gif"
  folder.iconImg.src = folder.iconSrc 
// alert(folder.iconImg.src);////////////////////////////////////////////////////////////////
  for (i=0; i<folder.nChildren; i++)
   folder.children[i].hide()
 } 
}

function hideFolder()
{
 if (browserVersion == 1) {
  if (this.navObj.style.display == "none")
   return
  this.navObj.style.display = "none"
 } else {
  if (this.navObj.visibility == "hiden")
   return
  this.navObj.visibility = "hiden"
 }
 
 this.setState(0)
}

function initializeFolder(level, lastNode, leftSide)
{
var j=0
var i=0
var numberOfFolders
var numberOfDocs
var nc
   
 nc = this.nChildren
 
 this.createIndex()

 var auxEv = ""

 if (browserVersion > 0)
  auxEv = "<a href='javascript:clickOnNode("+this.id+")' onMouseOver='winStatus(""); return true;' 'CLASS='menu'>"
 else
  auxEv = "<a>"

 if (level>0)
  if (lastNode) //the last 'brother' in the children array
  {
   this.renderOb(leftSide + auxEv + "<img name='nodeIcon" + this.id + "' src='images/ftv2mlastnode.gif' width=16 height=22 border=0></a>")
   leftSide = leftSide + "<img src='images/ftv2blank.gif' width=16 height=22>" 
   this.isLastNode = 1
  }
  else
  {
   this.renderOb(leftSide + auxEv + "<img name='nodeIcon" + this.id + "' src='images/ftv2mnode.gif' width=16 height=22 border=0></a>")
   leftSide = leftSide + "<img src='images/ftv2vertline.gif' width=16 height=22>"
   this.isLastNode = 0
  }
 else
  this.renderOb("")
 
 if (nc > 0)
 {
//alert(this.nChildren); ///////////////////////////////////////////////////////////////////////////////////////////////////////
  level = level + 1
  for (i=0 ; i < this.nChildren; i++) 
  {
   if (i == this.nChildren-1)
    this.children[i].initialize(level, 1, leftSide)
   else
    this.children[i].initialize(level, 0, leftSide)
   }
 }
}

function drawFolder(leftSide)
{
 if (browserVersion == 2) {
  if (!doc.yPos)
   doc.yPos=8
  doc.write("<layer id='folder" + this.id + "' top=" + doc.yPos + " visibility=hiden>")
 }
 
 doc.write("<table ")
 if (browserVersion == 1)
  doc.write(" id='folder" + this.id + "' style='position:block;' ")
 doc.write(" border=0 cellspacing=0 cellpadding=0>")
 doc.write("<tr><td>")
 doc.write(leftSide)
 this.outputLink()
 doc.write("<img name='folderIcon" + this.id + "' ")
 doc.write("src='" + this.iconSrc+"' height=16 width=16 border=0></a>")
 doc.write("</td><td valign=middle nowrap CLASS='contentList'>")
 if (USETEXTLINKS)
 {
  this.outputLink()
  doc.write("&nbsp;" + this.desc + "</a>")
 }
 else
  doc.write("&nbsp;" + this.desc)
 doc.write("</td>") 
 doc.write("</table>")
 
 if (browserVersion == 2) {
  doc.write("</layer>")
 }

 if (browserVersion == 1) {
  this.navObj = doc.all["folder"+this.id]
  this.iconImg = doc.all["folderIcon"+this.id]
  this.nodeImg = doc.all["nodeIcon"+this.id]
 } else if (browserVersion == 2) {
  this.navObj = doc.layers["folder"+this.id]
  this.iconImg = this.navObj.document.images["folderIcon"+this.id]
  this.nodeImg = this.navObj.document.images["nodeIcon"+this.id]
  doc.yPos=doc.yPos+this.navObj.clip.height
 }
}

function outputFolderLink()
{
 if (this.hreference)
 {
  //this link target always is conent
  doc.write("<a href='" + this.hreference + "' target="content"" + "' onMouseOver='winStatus("" + strRemoveHtml(this.desc) + ""); return true;' ")
  if (browserVersion > 0)
   doc.write("onClick='javascript:clickOnFolder("+this.id+")'")
  doc.write(">")
 }
 else
 //Modify by YCJ
  {
//  doc.write("<a>");
 doc.write("<a href='javascript:clickOnNode("+this.id+")' onMouseOver='winStatus("展开或者收缩【" + strRemoveHtml(this.desc) + "】项 "); return true;' class='menu'>" )
  }
}

function addChild(childNode)
{
 this.children[this.nChildren] = childNode
 this.nChildren++
 return childNode
}

function folderSubEntries()
{
 var i = 0
 var se = this.nChildren

 for (i=0; i < this.nChildren; i++){
  if (this.children[i].children) //is a folder
   se = se + this.children[i].subEntries()
 }

 return se
}


// Definition of class Item (a document or link inside a Folder)
// *************************************************************

function Item(itemDescription, itemLink) // Constructor
{
 // constant data
 descTemp_arr = itemDescription.split("^");
 this.desc= descTemp_arr[0] ;//strRemoveHtml(descTemp_arr[0]);
 // Assign the default icon if none specified
 //modify by YCJ
 if( descTemp_arr[1] == null ) {
this.iconSrc = "images/ftv2OneItem.gif";
 } else {
  this.iconSrc = descTemp_arr[1];
 }
 
 //this.desc = itemDescription
 this.link = itemLink
 this.id = -1 //initialized in initalize()
 this.navObj = 0 //initialized in render()
 this.iconImg = 0 //initialized in render()
// alert('desc= '+this.desc);
 this.initialize = initializeItem
 this.createIndex = createEntryIndex
 this.hide = hideItem
 this.display = display
 this.renderOb = drawItem
 this.totalHeight = totalHeight
}

function hideItem()
{
 if (browserVersion == 1) {
  if (this.navObj.style.display == "none")
   return
  this.navObj.style.display = "none"
 } else {
  if (this.navObj.visibility == "hiden")
   return
  this.navObj.visibility = "hiden"
 }  
}

function initializeItem(level, lastNode, leftSide)

 this.createIndex()

 if (level>0)
  if (lastNode) //the last 'brother' in the children array
  {
   this.renderOb(leftSide + "<img src='images/ftv2lastnode.gif' width=16 height=22>")
   leftSide = leftSide + "<img src='images/ftv2blank.gif' width=16 height=22>" 
  }
  else
  {
   this.renderOb(leftSide + "<img src='images/ftv2node.gif' width=16 height=22>")
   leftSide = leftSide + "<img src='images/ftv2vertline.gif' width=16 height=22>"
  }
 else
  this.renderOb("") 
}

function drawItem(leftSide)
{
 if (browserVersion == 2)
  doc.write("<layer id='item" + this.id + "' top=" + doc.yPos + " visibility=hiden>")
  
 doc.write("<table ")
 if (browserVersion == 1)
  doc.write(" id='item" + this.id + "' style='position:block;' ")
 doc.write(" border=0 cellspacing=0 cellpadding=0>")
 doc.write("<tr><td>")
 doc.write(leftSide)
 doc.write("<a href=" + this.link + " onMouseOver='winStatus("" + strRemoveHtml(this.desc) + ""); return true;'>")
 doc.write("<img id='itemIcon"+this.id+"' ")
 doc.write("src='"+this.iconSrc+"' border=0>")
 doc.write("</a>")
 doc.write("</td><td valign=middle nowrap CLASS='contentList'>")
 if (USETEXTLINKS)
  doc.write("<a href=" + this.link + " onMouseOver='winStatus("" + strRemoveHtml(this.desc) + ""); return true;'>&nbsp;" + this.desc + "</a>")
 else
  doc.write("&nbsp;" + this.desc)
 doc.write("</table>")
 
 if (browserVersion == 2)
  doc.write("</layer>")

 if (browserVersion == 1) {
  this.navObj = doc.all["item"+this.id]
  this.iconImg = doc.all["itemIcon"+this.id]
 } else if (browserVersion == 2) {
  this.navObj = doc.layers["item"+this.id]
  this.iconImg = this.navObj.document.images["itemIcon"+this.id]
  doc.yPos=doc.yPos+this.navObj.clip.height
 }
}


// Methods common to both objects (pseudo-inheritance)
// ********************************************************

function display()
{
 if (browserVersion == 1)
  this.navObj.style.display = "block"
 else
  this.navObj.visibility = "show"
}

function createEntryIndex()
{
 this.id = nEntries
 indexOfEntries[nEntries] = this
 nEntries++
}

// total height of subEntries open
function totalHeight() //used with browserVersion == 2
{
 var h = this.navObj.clip.height
 var i = 0
 
 if (this.isOpen) //is a folder and _is_ open
  for (i=0 ; i < this.nChildren; i++) 
   h = h + this.children[i].totalHeight()

 return h
}


// Events
// *********************************************************

function clickOnFolder(folderId)
{
 var clicked = indexOfEntries[folderId]

 if (!clicked.isOpen)
  clickOnNode(folderId)

 return 

 if (clicked.isSelected)
  return
}

function clickOnNode(folderId)
{
 var clickedFolder = 0
 var state = 0

 clickedFolder = indexOfEntries[folderId]
 state = clickedFolder.isOpen

 clickedFolder.setState(!state) //open<->close 
}

function initializeDocument()
{
 if (doc.all)
  browserVersion = 1 //IE4 
 else
  if (doc.layers)
   browserVersion = 2 //NS4
  else
   browserVersion = 0 //other

 foldersTree.initialize(0, 1, "")
 foldersTree.display()
 
 if (browserVersion > 0)
 {
  doc.write("<layer top="+indexOfEntries[nEntries-1].navObj.top+">&nbsp;</layer>")

  // close the whole tree
  clickOnNode(0)
  // open the root folder
  clickOnNode(0)
 }
}

// Auxiliary Functions for Folder-Treee backward compatibility
// *********************************************************

function gFld(description, hreference)
{
 folder = new Folder(description, hreference)
 return folder
}

function gLnk(target, description, linkData)
{
 fullLink = ""

 if (target==0)
 {
  fullLink = "'"+linkData+"' target="_top""
 }
 else
 {
  if (target==1)
    fullLink = "'http://"+linkData+"' target=_blank"
  else
    fullLink = "'"+linkData+"' target="content""
 }

 linkItem = new Item(description, fullLink) 
 return linkItem
}

function insFld(parentFolder, childFolder)
{
 return parentFolder.addChild(childFolder)
}

function insDoc(parentFolder, document)
{
 parentFolder.addChild(document)
}

// Global variables
// ****************

USETEXTLINKS = 1
indexOfEntries = new Array
nEntries = 0
doc = document
browserVersion = 0
selectedFolder=0