王朝网络
分享
 
 
 

基于JavaScript的树形菜单

王朝html/css/js·作者佚名  2006-01-30
宽屏版  字体: |||超大  

基于JavaScript的树形菜单

1 前言

显然,树形菜单在网络应用中是很重要的。我也到过国外专业的菜单开发网站看过,但是感觉可维护性很差。由于工作中的一些需要,我认为自己开发一个维护性好,接口简单的树形菜单是十分有用的。本文将详细介绍作者开发的基于JavaScript的树形菜单,并附上源代码。

2 基本功能

2.1 跨平台性能好

2.2 可维护性好

2.3 接口简单

2.4 能够表达子菜单

2.5 菜单显示时间不大于1ms/菜单项,响应时间亦如此。

3 基本分析

3.1 要求可维护性好,需采用完全的面向对象方法。

3.2 树形菜单完全由“菜单项”组成,“菜单项”由表达其类型(有无子菜单项)的开关图和表达其内容的文本,以及表达其事件响应的行为构成。开关图负责响应菜单项是否展开的事件。

3.3 树形菜单以及每个菜单项都使用table元素表示

4 设计

4.1 整个程序整合为一个treedefiniton.js文件,其中包含两个类(js称之为对象)。一个类是Tree,另一个是TreeItem,二者是一对多的关系。当然测试程序是一个test.htm文件。

4.2 程序的设计文档用reference.xml表示,版本信息(包含作者)用versions.xml表示。所有xml的结构尚未固定,仅有用于显示的reference.xsl以及versions.xsl.这些程序的源代码限于篇幅,未公布于此。

4.3 TreeItem设计 TreeItem

TreeItem

public methods

TreeItem()

addItem()

public attributes

text

action

children

tree

type

id

Description

An instance of this class is corresponding to an menu item on a tree menu.

public methods

TreeItem(text,action)

functions

CONSTRUCTOR

arguments

text

type:

string

description:

to be shown

action

type:

string

description:

The action will be performed when the item is clicked. It will be the onclick property of a html element. CAUTION:DON'T PUT CHAR ' TO IT.

addItem()

functions

Let the menuitems specified by the arguments be the subitems of this menuitem. Their orders are determined by the orders of the correponding arguments.

arguments

type:

TreeItem

description:

There is no limit on the number of arguments, but each argument should be an instance of Class MenuItem.

public attributes

1

text

string

set by the first argument of CONSTRUCTOR. Only for Class Tree.

2

action

string

set by the second argument of CONSTRUCTOR. Only for Class Tree.

3

children

Array

all subitems, set by addChild() method. Only for Class Tree.

4

tree

Tree

the tree to which the item belongs. Only for Class Tree.

5

type

string

should be one of Tree.FILE_TYPE and Tree.FOLDER_TYPE. Only for Class Tree.

6

id

string

id property of the element corresponding to this item. Only for Class Tree.

4.4 Tree设计 Tree

Tree

CONSTANTS

VERSION

AUTHOR

FILE_IMAGE

FOLDER_IMAGE

UNFOLD_IMAGE

VERSIONS

REFERENCE

FILE_TYPE

FOLDER_TYPE

public methods

Tree()

getHtml()

public attributes

indent

withSelfItem

itemColor

itemBackground

selectedItemBackground

root

selfItem

versionsItem

referenceItem

private attributes

name

html

elementClicked

private methods

findItem

findUnderlines

click

Description

An instance of this class is corresponding to a tree menu.

CONSTANTS

1

VERSION

string

"1.08"

version number

2

AUTHOR

string

"liaomingxue"

author name

3

FILE_IMAGE

string

"images/file.gif"

relative path of an image file for menu item with no subitems

4

FOLDER_IMAGE

string

"images/fold.gif"

relative path of an image file for menu item having visible subitems

5

UNFOLD_IMAGE

string

"images/unfold.gif"

relative path of an image file for menu item with its invisible subitems

6

VERSIONS

string

"aboutTree/versions.xml"

relative path of file used to show what progresses happened in all versions of this program.

7

REFERENCE

string

"aboutTree/class.xml"

relative path of file used to introduce the design of the classes of this program.

8

FILE_TYPE

string

"FILE"

an option for type atrribute of Class TreeItem

9

FOLDER_TYPE

string

"FOLDER"

an option for type atrribute of Class TreeItem

public methods

Tree(instanceName,text,action)

functions

CONSTRUCTOR

arguments

instanceName

type:

string

description:

the name of the instance 'this'

text

type:

string

description:

the text property of root item of Tree

action

type:

string

description:

the action property of root item of Tree

getHtml()

functions

to get html property of Tree

public attributes

1

indent

integer

for indenting subitem, greater than 0

2

withSelfItem

boolean

if true, show selfItem

3

itemColor

string

text color of item, eg. "#888888"

4

itemBackground

string

background color of item

5

selectedItemBackground

string

background color of item clicked

6

root

TreeItem

root item

7

selfItem

TreeItem

for demonstrating information about this program

8

versionsItem

TreeItem

selfItem's subitem to tell information about all versions

9

referenceItem

TreeItem

selfItem's subitem to show Classes designing

private attributes

1

name

string

set by argument 1

2

html

string

the content(in html format) to be shown

3

elementClicked

string

hold the id property of which item clicked

private methods

findItem(id)

arguments

id

type:

string

description:

the id of what item you want to find

findUnderlines(str)

arguments

str

type:

string

description:

return

type:

integer

description:

return how many underlines '_' occur in the argument

click(itemID)

functions

respond to item click event

arguments

itemID

type:

string

description:

id property of the clicked item

4.5 一些补充

4.5.1对于TreeItem的public attributes,显然是不能都作为public的,这里这样处理的原因是我认为程序的功能尚未达到需要严格定义的程度。

4.5.2 根菜单项。树形菜单只有一个根菜单项,其他所有菜单项都是它的子菜单项。

4.5.3 菜单项的id。根菜单项的id仅含一个下划线,其余类推之。

4.5.4 用到的图标资源为

,类似于csdn,是我自己画的。

5 性能

在菜单项达到48项时候,显示时间基本达到要求,响应时间好于要求。

6 总结

自己并不是专业做这个的,所以公布这个源代码,希望能够让大家做好这个东西。目前最新版本是1.12. 任何进一步改进该程序的程序员,我将在versions.xml中注明该程序员。原则上每次改进,版本号将增加0.01.限于个人能力,所有改进只能通过e-mail,且,所有改进都将在这篇文章中公布。我的email是mxliao@mails.gscas.ac.cn。暂时由我管理所有改进。如有朋友提供空间,我将感激不尽,并将适时采取其他程序管理方法。

由于本程序的设计者和实现者都是我一人,以及时间有限,所以这里设计和实现的衔接可能有不完备或者不一致的地方,请见谅。

7 测试程序源代码片断(test.htm)

var tree=new Tree("tree","Words Expert","");

tree.root.addChild((Add=new TreeItem("Add","")),

(Recite=new TreeItem("Recite","")),

(View=new TreeItem("View","")),

(Help=new TreeItem("Help","")),

(Config=new TreeItem("Config","")),

(File=new TreeItem("File","")),

(About=new TreeItem("About Words Expert","")));

Recite.addChild((seeChinese=new TreeItem("See Chinese","")),

(seeEnglish=new TreeItem("See English","")),

(lastOrder=new TreeItem("Last order","")));

seeChinese.addChild((reciteChineseAlpha=new TreeItem("Alpha","")),

(reciteChineseFamiliarity=new TreeItem("Familiarity","")),

(reciteChineseTime=new TreeItem("Time","")));

reciteChineseAlpha.addChild(

(new TreeItem("Alpha Order","")),

(new TreeItem("Reverse Alpha Order","")));

reciteChineseFamiliarity.addChild(

(new TreeItem("Familiarity","")),

(new TreeItem("Reverse Reverse Familiarity","")));

reciteChineseTime.addChild(

(new TreeItem("Time","")),

(new TreeItem("Reverse Time","")));

seeEnglish.addChild((reciteEnglishAlpha=new TreeItem("Alpha","")),

(reciteEnglishFamiliarity=new TreeItem("Familiarity","")),

(reciteEnglishTime=new TreeItem("Time","")));

reciteEnglishAlpha.addChild(

(new TreeItem("Alpha Order","")),

(new TreeItem("Reverse Alpha Order","")));

reciteEnglishFamiliarity.addChild(

(new TreeItem("Familiarity","")),

(new TreeItem("Reverse Reverse Familiarity","")));

reciteEnglishTime.addChild(

(new TreeItem("Time","")),

(new TreeItem("Reverse Time","")));

View.addChild(

(lastOrder=new TreeItem("Last Order","")),

(alpha=new TreeItem("Alpha","")),

(familiarity=new TreeItem("Familiarity","")),

(time=new TreeItem("Time","")));

alpha.addChild(

(new TreeItem("Alpha Order","")),

(new TreeItem("Reverse Alpha Order","")));

familiarity.addChild(

(new TreeItem("Familiarity Order","")),

(new TreeItem("Reverse Familiarity Order","")));

time.addChild(

(new TreeItem("Time Order","")),

(new TreeItem("Reverse Time Order","")));

File.addChild((new TreeItem("Save wordbook","")), (new TreeItem("Save config","")),(new TreeItem("Save All","")),(new TreeItem("Save All & Exit","")),

(new TreeItem("Exit Without Saving","")),

(new TreeItem("Backup wordbook","")));

tree.show();

8 TreeDefinition.js源代码(7K)

function TreeItem(text,action)

{

// public attributes

this.text=text;

this.action=action;

this.children=new Array();

this.tree=null;

this.type="";

this.id="";

// public methods

this.addChild=TreeItem_addChild;

}

function Tree(instanceName,text,action)

{

// constants

this.VERSION="1.12";

this.AUTHOR="liaomingxue";

this.FILE_IMAGE="images/file.gif";

this.FOLDER_IMAGE="images/fold.gif";

this.UNFOLD_IMAGE="images/unfold.gif";

this.VERSIONS="aboutTree/versions.xml";

this.REFERENCE="aboutTree/class.xml";

this.FILE_TYPE="FILE";

this.FOLDER_TYPE="FOLDER";

// priavate attributes

this.name=instanceName;

this.html="";

this.elementClicked="";

// public attributes

this.indent=20;

this.withSelfItem=true;

this.itemColor="#000000";

this.itemBackground="#aaafff";

this.itemOverColor="#0000ff";

this.selectedItemBackground="#ccaacc";

this.root=new TreeItem(text,action);

this.root.id="TREEMENU"+"_0";

this.root.tree=this;

this.selfItem=new TreeItem("ABOUT TREE MENU","");

this.versionsItem=new TreeItem("versions","window.open(\""+this.VERSIONS+"\")");

this.referenceItem=new TreeItem("programmer reference","window.open(\""+this.REFERENCE+"\")");

// private methods

this.findItem=Tree_findItem;

this.findUnderlines=Tree_findUnderlines;

this.click=Tree_click;

// public methods

this.show=TREE_show;

this.getHtml=function getHtml(){return this.html;}

}

function Tree_findUnderlines(str)

{

var i,j;

for(i=0,j=0;i<str.length;i++) if(str.charAt(i)==='_') j++;

return j;

}

function TreeItem_addChild()

{

var child;

var i;

for(i=0;i<arguments.length;i++)

{

child=arguments[i];

this.children[this.children.length]=child;

this.type=this.tree.FOLDER_TYPE;

child.id=this.id+"_"+(this.children.length-1);

child.tree=this.tree;

child.type=this.tree.FILE_TYPE;

}

}

function TREE_show()

{

this.html+="<table cellspacing=0 cellpadding=0 rules='cols' style='border-width:2;' height='100%'>";

this.html+="<tr><td>";

this.html+="<table cellspacing=0 cellpadding=0>";

var n,i,top,stack;

this.root.addChild(this.selfItem);

this.selfItem.addChild(this.versionsItem,this.referenceItem);

stack=new Array(); //初始化目录栈

stack[0]=this.root; //加入目录栈的栈顶目录

while(stack.length>0)

{

/*弹出栈顶元素,并保存到top变量*/

top=stack[stack.length-1];

stack.length--;

n=this.findUnderlines(top.id);

/*将弹出的栈顶元素作为一个目录加入*/

this.html+="<tr style='";

if(n<3) this.html+=" display:;'>";

else this.html+=" display:none;'>";

this.html+="<td>";

this.html+=" <table style='table-layout:fixed;' cellspacing=0 cellpadding=0 id='"+top.id+"'";

this.html+=" <tr style='background:"+this.itemBackground+";'>";

for(i=0;i<n-1;i++)

this.html+=" <td width="+this.indent+">&nbsp;</td>";

this.html+=" <td nowrap>";

this.html+=" <img style='cursor:hand;' onclick='"+this.name+".click(this.parentNode.parentNode.parentNode.parentNode.id);' border=0 src='";

if(top.type==this.FOLDER_TYPE)

if(n==1)

this.html+=this.UNFOLD_IMAGE+"'>";

else this.html+=this.FOLDER_IMAGE+"'>";

else this.html+=this.FILE_IMAGE+"'>";

this.html+= "</img>";

this.html+=" <a onmouseover='this.style.color=\""+this.itemOverColor+"\";'";

this.html+=" onmouseout='this.style.color=\""+this.itemColor+"\";'";

this.html+=" style='color:"+this.itemColor+";cursor=hand;font-family:times new roman;font-size:medium;font-weight:bold;''"

this.html+=" onclick='"+top.action+"'>"+top.text;

this.html+=" </a>";

this.html+=" </td>";

this.html+=" </tr>";

this.html+=" </table>";

this.html+="</tr></td>";

/*假如弹出的栈顶目录有子目录,应该按逆序把所有子目录加到栈中*/

for(i=top.children.length-1;i>=0;i--) stack[stack.length]=top.children[i];

}

this.html+="</table>";

this.html+="</td></tr>";

this.html+="<tr><td height='100%' style='background:"+this.itemBackground+";'>&nbsp;</td></tr>";

this.html+="</table>";

document.write(this.html);

}

function Tree_click(itemID)

{

/* 首先找到被单击的html元素 */

var e=window.event.srcElement;

/* 找到该元素对应的目录对象 */

var item=this.findItem(itemID);

if(item!=null)

{

/* 如果该目录的类型为文件夹,那么,当它已经展开时,应折叠,否则相反 */

var i,s;

//如果被单击的是文件夹类型的目录

if(item.type==this.FOLDER_TYPE)

{

//如果该文件夹没有展开

if(e.src.indexOf(this.FOLDER_IMAGE)>=0)

{

//首先展开它,也就是更换它的图像

e.src=this.UNFOLD_IMAGE;

var stack=new Array(); //初始化目录栈

//先将所有一级子目录加到栈中

for(i=item.children.length-1;i>=0;i--) stack[stack.length]=item.children[i];

var top;

while(stack.length>0)

{

/*弹出一个目录*/

top=stack[stack.length-1];stack.length--;

document.all(top.id).parentNode.parentNode.style.display=""; //显示它

//如果这个被显示的目录处于展开状态,那么它的所有一级子目录应该加到栈中

if(top.type==this.FOLDER_TYPE &&

document.all(top.id).firstChild.firstChild.lastChild.firstChild.src.indexOf(this.UNFOLD_IMAGE)>=0)

for(i=top.children.length-1;i>=0;i--) stack[stack.length]=top.children[i];

}

}

/* 如果该文件夹已经展开 */

else

{

//首先折叠它

e.src=this.FOLDER_IMAGE;

//然后隐藏它的所有子目录,这里用到一个栈,来求出所有子目录

var stack=new Array(); //初始化目录栈

//先将所有一级子目录加到栈中

for(i=item.children.length-1;i>=0;i--)

stack[stack.length]=item.children[i];

var top;

while(stack.length>0)

{

/*弹出一个目录*/

top=stack[stack.length-1];stack.length--;

document.all(top.id).parentNode.parentNode.style.display="none"; //隐藏它

//再将这个被隐藏的目录的所有一级子目录加到栈中

for(i=top.children.length-1;i>=0;i--) stack[stack.length]=top.children[i];

}

}

}

/*如果以前有被单击的目录,那么以前被单击的元素要恢复到未单击的状态*/

if(this.elementClicked.length!=0)

document.all(this.elementClicked).firstChild.firstChild.lastChild.lastChild.style.background=this.itemBackground;

this.elementClicked=itemID;

document.all(this.elementClicked).firstChild.firstChild.lastChild.lastChild.style.background=this.selectedItemBackground;

}

}

function Tree_findItem(id)

{

/*从根目录开始找*/

var root=this.root;

var item=root;

if(item.id==id) return item;

var i;

for(i=0;i<root.children.length;i++)

{

item=root.children[i];

/*正好找到*/

if(item.id==id) return item;

/*

如果这个目录的层次大于或者等于要找的目录的层次,那么就不必再找了。

由于目录的层次与目录的id中的下划线个数相同,所以可以用这种方法

*/

if(this.findUnderlines(item.id)>this.findUnderlines(id)) return null;

/*如果找到它的一个直系祖先,那么就应该马上从它的直系祖先开始找下去*/

if(id.indexOf(item.id)==0 && id.charAt(item.id.length)=='_')

{

i=-1;root=item;

}

}

return null;

}

9 版本信息(自从1.05) Versions of TreeMenuBy liaomingxue Version Number Time Description 1.05 2004.7.20 Eliminated some unnecessary attributes of Class Tree. Now I use xml to present version information and programer reference. The files are within dir aboutTree. The action property of the slefItem of Tree has changed to open a new window to show versions.xml which dwells in dir aboutTree. But Classes' UML presentations are unavailabe at present. Maybe the next version. 1.06 2004.7.20 Eliminated the attribute parent from Class TreeItem. UML diagram of class TreeItem, available. 1.07 2004.7.21 UML diagram beautified. File versions.xsl modified. 1.08 2004.7.21 Class TreeItem changed. No change on TreeItem's functionality.UML diagram of class TreeItem changed. 1.09 2004.7.21 simplified the Class Tree. The former vesions let an "IMG" html element be within an "A" element, now "A" removed. This results in an about 1/8 decrease in length of html property of Tree. 1.10 2004.7.21 Now there is no id property for Tree 1.11 2004.7.22 UML representation of Class Tree, available 1.12 2004.7.23 Redundant information removed to suit the release in CSDN. Some code polished. 10 测试程序演示图

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有