搜档网
当前位置:搜档网 › 多叉树结合JavaScript树形控件实现无限级树形菜单(一种构建多级有序树形结构JSON(或XML)数据源的方法)

多叉树结合JavaScript树形控件实现无限级树形菜单(一种构建多级有序树形结构JSON(或XML)数据源的方法)

多叉树结合JavaScript树形控件实现无限级树形菜单(一种构建多级有序树形结构JSON(或XML)数据源的方法)
多叉树结合JavaScript树形控件实现无限级树形菜单(一种构建多级有序树形结构JSON(或XML)数据源的方法)

多叉树结合JavaScript树形控件实现无限级树形菜单(一种构建多级有序树形结构JSON(或XML)数据源的方法)

一、问题研究的背景和意义

在Web应用程序开发领域,基于AJAX技术的JavaScript树形控件已经被广泛使用,它用来在Html页面上展现具有层次结构的数据项。目前市场上常见的JavaScript框架及组件库中均包含自己的树形控件,例如JQuery、Dojo、Yahoo UI、Ext JS等,还有一些独立的树形控件,例如dhtmlxtree等,这些树形控件完美的解决了层次数据的展示问题。展示离不开数据,树形控件主要利用AJAX技术从服务器端获取数据源,数据源的格式主要包括JSON、XML等,而这些层次数据一般都存储在数据库中。“无限级树形菜单”,顾名思义,没有级别的限制,它的数据通常来自数据库中的无限级层次数据,这种数据的存储表通常包括id和parentId这两个字段,以此来表示数据之间的层次关系。现在问题来了,既然树形控件的数据源采用JSON或XML等格式的字符串来组织层次数据,而层次数据又存储在数据库的表中,那么如何建立起树形控件与层次数据之间的关系,换句话说,如何将数据库中的层次数据转换成对应的层次结构的JSON或XML格式的字符串,返回给客户端的JavaScript 树形控件?这就是我们要解决的关键技术问题。本文将以目前市场上比较火热的Ext JS框架为例,讲述实现无限级树形菜单的方法,该方法同样适用于其它类似的JS树形控件。

Ext JS框架是富客户端开发中出类拔萃的框架之一。在Ext的UI控件中,树形控件无疑是最为常用的控件之一,它用来实现树形结构的菜单。TreeNode用来实现静态的树形菜单,AsyncTreeNode用来实现动态的异步加载树形菜单,后者最为常用,它通过接收服务器端返回来的JSON格式的数据,动态生成树形菜单节点。动态生成树有两种思路:一种是一次性生成全部树节点,另一种是逐级加载树节点(利用AJAX,每次点击节点时查询下一级节点)。对于大数据量的菜单节点来说,逐级加载是比较合适的选择,但是对于小数据量的菜单来说,一次性生成全部节点应该是最为合理的方案。在实际应用开发中,一般不会遇到特别大数据量的场景,所以一次性生成全部菜单节点是我们重点研究的技术点,也就是本文要解决的关键技术问题。本文以基于Ext JS的应用系统为例,讲述如何将数据库中的无限级层次数据一次性在界面中生成全部菜单节点(例如在界面中以树形方式一次性展示出银行所有分支机构的信息),同时对每一个层次的菜单节点按照某一属性和规则排序,展示出有序的菜单树。

解决一次性构造无限级树形菜单的问题,可以拓展出更多的应用场景,例如树形结构表格TreeGrid,一次性生成树形表格,对树形表格进行完整分页,对表格列进行全排序;或者可以利用本文的思路扩展出其他的更复杂的应用场景。

先看两个图例,有个直观上的认识:

图一,银行分支机构树形结构菜单

图二,树形结构表格

二、详细设计方案

让我们先看两段代码片段:

以上两个程序文件是一次性生成无限级树形菜单所必须的,其中最为关键的部分就是如何生成一个无限级的树形结构JSON字符串,返回给客户端的Ext树形控件。对于银行分支机构来说,需要返回类似如下的JSON串:

{

id : '100000',

text : '廊坊银行总行',

children : [

{

id : '110000',

text : '廊坊分行',

children : [

{

id : '113000',

text : '廊坊银行开发区支行',

leaf : true

},

{

id : '112000',

text : '廊坊银行解放道支行',

children : [

{

id : '112200',

text : '廊坊银行三大街支行',

leaf : true

},

{

id : '112100',

text : '廊坊银行广阳道支行',

leaf : true

}

]

},

{

id : '111000',

text : '廊坊银行金光道支行',

leaf : true

}

]

}

]

}

同时还需要对树中每一个层次的节点按照某一属性(比如分支机构编号)进行排序,以展示出有序的树形菜单。

现在可以把问题概括为:

1、把数据库中的层次数据转换成多级树形结构的JSON格式的字符串

2、对树中每一个层次的节点按照某一属性(比如分支机构编号)进行排序

下面介绍解决问题的思路:

在数据结构这门课中,我们都学过树,无限级树形菜单就可以抽象成一种多叉树结构,即每个节点下包含多个子节点的树形结构,首先就需要把数据库中的层次数据转换成多叉树结构的对象树,也就是构造出一棵多叉树。

有了数据结构,还要实现相应的算法,我们需要实现两种算法:

1、兄弟节点横向排序算法,对隶属于同一个父节点下面的所有直接子节点按照某一节点属性和规则进行排序,保持兄弟节点横向有序;

2、先序遍历算法,递归打印出无限级JSON字符串。

概括起来分为三步:

1、构造无序的多叉树结构

2、实现兄弟节点横向排序方法

3、实现先序遍历方法,打印出JSON字符串

如图所示:

我们给这棵树起个名字吧,就叫做multiple tree ,简称M-Tree。

三、源代码实现(Java语言版)

实现这样一颗树,需要设计三个类:树类(MultipleTree.java)、节点类(Node.java)、孩子列表类(Children.java);为了方便演示,还需要构造一些假的层次数据,因此还需要建一个构造假数据的类(VirtualDataGenerator.java),以下代码拷贝出来之后可直接运行测试:

package test;

import java.util.ArrayList;

import https://www.sodocs.net/doc/c516733814.html,parator;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.Set;

import java.util.Collections;

/**

* 多叉树类

*/

public class MultipleTree {

public static void main(String[] args) {

// 读取层次数据结果集列表

List dataList = VirtualDataGenerator.getVirtualResult();

// 节点列表(散列表,用于临时存储节点对象)

HashMap nodeList = new HashMap();

// 根节点

Node root = null;

// 根据结果集构造节点列表(存入散列表)

for (Iterator it = dataList.iterator(); it.hasNext();) {

Map dataRecord = (Map) it.next();

Node node = new Node();

node.id = (String) dataRecord.get("id");

node.text = (String) dataRecord.get("text");

node.parentId = (String) dataRecord.get("parentId");

nodeList.put(node.id, node);

}

// 构造无序的多叉树

Set entrySet = nodeList.entrySet();

for (Iterator it = entrySet.iterator(); it.hasNext();) {

Node node = (Node) ((Map.Entry) it.next()).getValue();

if (node.parentId == null || node.parentId.equals("")) {

root = node;

} else {

((Node) nodeList.get(node.parentId)).addChild(node);

}

}

// 输出无序的树形菜单的JSON字符串

System.out.println(root.toString());

// 对多叉树进行横向排序

root.sortChildren();

// 输出有序的树形菜单的JSON字符串

System.out.println(root.toString());

// 程序输出结果如下(无序的树形菜单)(格式化后的结果):

// {

// id : '100000',

// text : '廊坊银行总行',

// children : [

// {

// id : '110000',

// text : '廊坊分行',

// children : [

// {

// id : '113000',

// text : '廊坊银行开发区支行',

// leaf : true

// },

// {

// id : '111000',

// text : '廊坊银行金光道支行',

// leaf : true

// },

// {

// id : '112000',

// text : '廊坊银行解放道支行',

// children : [

// {

// id : '112200',

// text : '廊坊银行三大街支行', // leaf : true

// },

// {

// id : '112100',

// text : '廊坊银行广阳道支行', // leaf : true

// }

// ]

// }

// ]

// }

// ]

// }

// 程序输出结果如下(有序的树形菜单)(格式化后的结果):

// {

// id : '100000',

// text : '廊坊银行总行',

// children : [

// {

// id : '110000',

// text : '廊坊分行',

// children : [

// {

// id : '111000',

// text : '廊坊银行金光道支行',

// leaf : true

// },

// {

// id : '112000',

// text : '廊坊银行解放道支行',

// children : [

// {

// id : '112100',

// text : '廊坊银行广阳道支行', // leaf : true

// },

// {

// id : '112200',

// text : '廊坊银行三大街支行', // leaf : true

// }

// ]

// },

// {

// id : '113000',

// text : '廊坊银行开发区支行',

// leaf : true

// }

// ]

// }

// ]

// }

}

}

/**

* 节点类

*/

class Node {

/**

* 节点编号

*/

public String id;

/**

* 节点内容

*/

public String text;

/**

* 父节点编号

*/

public String parentId;

/**

* 孩子节点列表

*/

private Children children = new Children();

// 先序遍历,拼接JSON字符串

public String toString() {

String result = "{"

+ "id : '" + id + "'"

+ ", text : '" + text + "'";

if (children != null && children.getSize() != 0) {

result += ", children : " + children.toString();

} else {

result += ", leaf : true";

}

return result + "}";

}

// 兄弟节点横向排序

public void sortChildren() {

if (children != null && children.getSize() != 0) {

children.sortChildren();

}

}

// 添加孩子节点

public void addChild(Node node) {

this.children.addChild(node);

}

}

/**

* 孩子列表类

*/

class Children {

private List list = new ArrayList();

public int getSize() {

return list.size();

}

public void addChild(Node node) {

list.add(node);

}

// 拼接孩子节点的JSON字符串

public String toString() {

String result = "[";

for (Iterator it = list.iterator(); it.hasNext();) {

result += ((Node) it.next()).toString();

result += ",";

}

result = result.substring(0, result.length() - 1);

result += "]";

return result;

}

// 孩子节点排序

public void sortChildren() {

// 对本层节点进行排序

// 可根据不同的排序属性,传入不同的比较器,这里传入ID比较器

Collections.sort(list, new NodeIDComparator());

// 对每个节点的下一层节点进行排序

for (Iterator it = list.iterator(); it.hasNext();) {

((Node) it.next()).sortChildren();

}

}

}

/**

* 节点比较器

*/

class NodeIDComparator implements Comparator {

// 按照节点编号比较

public int compare(Object o1, Object o2) {

int j1 = Integer.parseInt(((Node)o1).id);

int j2 = Integer.parseInt(((Node)o2).id);

return (j1 < j2 ? -1 : (j1 == j2 ? 0 : 1));

}

}

/**

* 构造虚拟的层次数据

*/

class VirtualDataGenerator {

// 构造无序的结果集列表,实际应用中,该数据应该从数据库中查询获得;

public static List getVirtualResult() {

List dataList = new ArrayList();

HashMap dataRecord1 = new HashMap();

dataRecord1.put("id", "112000");

dataRecord1.put("text", "廊坊银行解放道支行");

dataRecord1.put("parentId", "110000");

HashMap dataRecord2 = new HashMap();

dataRecord2.put("id", "112200");

dataRecord2.put("text", "廊坊银行三大街支行");

dataRecord2.put("parentId", "112000");

HashMap dataRecord3 = new HashMap();

dataRecord3.put("id", "112100");

dataRecord3.put("text", "廊坊银行广阳道支行");

dataRecord3.put("parentId", "112000");

HashMap dataRecord4 = new HashMap();

dataRecord4.put("id", "113000");

dataRecord4.put("text", "廊坊银行开发区支行");

dataRecord4.put("parentId", "110000");

HashMap dataRecord5 = new HashMap();

dataRecord5.put("id", "100000");

dataRecord5.put("text", "廊坊银行总行");

dataRecord5.put("parentId", "");

HashMap dataRecord6 = new HashMap();

dataRecord6.put("id", "110000");

dataRecord6.put("text", "廊坊分行");

dataRecord6.put("parentId", "100000");

HashMap dataRecord7 = new HashMap();

dataRecord7.put("id", "111000");

dataRecord7.put("text", "廊坊银行金光道支行");

dataRecord7.put("parentId", "110000");

dataList.add(dataRecord1);

dataList.add(dataRecord2);

dataList.add(dataRecord3);

dataList.add(dataRecord4);

dataList.add(dataRecord5);

dataList.add(dataRecord6);

dataList.add(dataRecord7);

return dataList;

}

}

好了,通过上面的代码,就可以实现多叉树的兄弟节点横向排序和先序遍历了,实现了将层次数据转换为有序无限级树形结构JSON字符串的目的。

在实际的项目中,可以把上面的有效代码融入其中,或者在此基础上进行一些扩展:

1、实现对指定层次的排序(例如只排序第一层的节点,或者只排序某一父节点下的所有子

节点)

2、遍历输出树形结构时可以加入判断条件过滤掉某些节点

3、实现节点的删除功能

4、在节点类中增加一个父节点的引用,就可以计算出某一节点所处的级别

5、在不支持层次查询(hierarical retrival)的数据库应用系统中使用该算法实现相同的效果

四、思考与总结

这篇文章的重点是如何构造有序的无限级的树形结构JSON字符串,一次性生成树形菜单,而不是利用AJAX的方式,反复向服务器端发送请求,一级接一级的加载树节点。

既然可以构造无限级的JSON字符串,那么也可以根据这个思路构造无限级的XML字符串,或者构造具有层次结构的UL – LI组合(用UL - LI来展示树形结构),或者构造具有层次结构的TABLE(用TABLE来展示树形结构)。如下所示:

(1)XML层次结构

(2)UL - LI 层次结构

  • 廊坊银行总行
    • 廊坊分行
      • 廊坊银行开发区支行
      • 廊坊银行解放道支行
        • 廊坊银行三大街支行
        • 廊坊银行广阳道支行

      • 廊坊银行金光道支行

(3)TABLE层次结构

廊坊银行总行
  廊坊分行
    廊坊银行开发区支行
    廊坊银行解放道支行
      廊坊银行三大街支行
      廊坊银行广阳道支行
    廊坊银行金光道支行

另外对TreeGrid树形表格也有一定的价值:

1、一次性构造树形表格,实现数据分级展示

2、通过更换比较器,实现对不同表格列的全排序(全排序指的是对所有页的数据进行排序,

而不是只对当前页的数据排序)

3、实现对树形表格的完整分页(每次分页时,只取固定数目的第一层节点,之后调用

toString方法,展示出完整条数的分级数据)

五、参考书籍

1、Mark Allen Weiss,数据结构与算法分析(Java语言描述)

2、Bruce Eckel,Thinking In Java Third Edition

3、David Flanagan,JavaScript: The Definitive Guide, 5th Edition

4、OCA Oracle Database 11g SQL Fundamentals I Exam Guide

5、侯捷,重构-改善既有代码的设计

注:本文的思路方法是是受到Oracle层次查询的启发,所以将《OCA Oracle Database 11g SQL Fundamentals I Exam Guide》这本书也写在了参考书籍里面,以表示对Oracle的感谢。构造多叉树的方法是从数据结构中获得灵感,故也把《数据结构与算法分析(Java语言描述)》这本书列了出来,以示感谢。

六、联系方式

memorymultitree@https://www.sodocs.net/doc/c516733814.html,

ASP NET+TreeView树型菜单操作实例(代码调试通过)

https://www.sodocs.net/doc/c516733814.html, TreeView树型菜单操作实例(代码调试通过) 本实例完成TreeView树型菜单添加,修改,删除,绑定DropDownList功能,移动功能读者可以自行书写.aspx代码

TreeView操作实例
节点名

竖型导航栏的制作

竖型导航栏的制作 1、新建html文件index.html,使用文本编辑器进行编辑。如下图: 2、在内开始编写导航栏的html代码。使用ul标签建立一个无序列表

效果如下图: 此时的列表还不能点击进行导航,我们使用标签进行超链接:

效果如下图: 3、为了使得导航栏更加美观我用CSS进行样式设计,此时应在标签里进 行引用。 4、新建CSS文件使用文本编辑器进行编辑 A.应为html页面默认有内、外边距。为方便我们进行样式设计,把所有标 签默认的内、外边距设为0px。 *{ margin:0px; padding:0px; } B.为了使导航栏在页面中间我们通过设置列表所在的

标签的属性实现 #main { width:900px; margin:50px auto; position:relative } C.为了导航栏突出于页面我们对列表标签整体进行设计 .nav { height:320px; width:150px; background:#90BADE; border-right:1px solid #333; margin:0 auto; } 效果如下图:

js树形菜单代码

a {text-decoration:none;} a,a:visited {color:#000;background:inherit;} body {margin:0;padding:20px;font:12px tahoma,宋体,sans-serif;} dt {font-size:22px;font-weight:bold;margin:0 0 0 15px;} dd {margin:0 0 0 15px;} h4 {margin:0;padding:0;font-size:18px;text-align:center;} p {margin:0;padding:0 0 0 18px;} p a,p a:visited {color:#00f;background:inherit;} /*CNLTreeMenu Start*/ .CNLTreeMenu img.s {cursor:pointer;vertical-align:middle;} .CNLTreeMenu ul {padding:0;} .CNLTreeMenu li {list-style:none;padding:0;} .Closed ul {display:none;} .Child img.s {background:none;cursor:default;} #CNLTreeMenu1 ul {margin:0 0 0 17px;} #CNLTreeMenu1 img.s {width:20px;height:15px;} #CNLTreeMenu1 .Opened img.s {background:url(skin1/opened.gif) no-repeat 0 0;} #CNLTreeMenu1 .Closed img.s {background:url(skin1/closed.gif) no-repeat 0 0;} #CNLTreeMenu1 .Child img.s {background:url(skin1/child.gif) no-repeat 3px 5px;} #CNLTreeMenu2 ul {margin:0 0 0 17px;} #CNLTreeMenu2 img.s {width:17px;height:15px;} #CNLTreeMenu2 .Opened img.s {background:url(skin2/opened.gif) no-repeat 4px 6px;} #CNLTreeMenu2 .Closed img.s {background:url(skin2/closed.gif) no-repeat 3px 6px;} #CNLTreeMenu2 .Child img.s {background:url(skin2/child.gif) no-repeat 3px 5px;} #CNLTreeMenu3 ul {margin:0 0 0 17px;} #CNLTreeMenu3 img.s {width:34px;height:18px;} #CNLTreeMenu3 .Opened img.s {background:url(skin3/opened.gif) no-repeat 0 1px;} #CNLTreeMenu3 .Closed img.s {background:url(skin3/closed.gif) no-repeat 0 1px;} #CNLTreeMenu3 .Child img.s {background:url(skin3/child.gif) no-repeat 13px 2px;} /*CNLTreeMenu End*/ /*Temp CSS for View Demo*/ #CNLTreeMenu1,#CNLTreeMenu2,#CNLTreeMenu3 {float:left;width:249px;border:1px solid #99BEEF;background:#D2E4FC;color:inherit;margin:3px;padding:3px;} #CNLTreeMenu1,#CNLTreeMenu2 {padding-bottom:15px;} .ViewCode { clear:both; border:1px solid #FFB900;background:#FFFFCC;color:inherit;margin:3px;padding:3px; } .ViewCode h6 {color:#00f;}

纵向导航菜单

今天我们开始学习《十天学会web标准(div+css)》的纵向导航菜单及二级弹出菜单,包含以下内容和知识点: ■纵向列表 ■标签的默认样式 ■css派生选择器 ■css选择器的分组 ■纵向二级列表 ■相对定位和绝对定位 一、纵向列表 纵向列表或称为纵向导航,在网站的产品列表中应用比较广泛,如淘宝网左侧的淘宝服务,今天我们就学习一下纵向导航的制作 先新建一个页面,然后插入一个ID为menu的div,然后在设计视图中选中文字,点击工具栏的ul图标,即会自动插入ul和li,然后修改文字内容为你需要的内容。

从预览的效果上看,四周都有很大的空隙,而且每一行前边还有个点,这是因为标签的默认样式造成的,下面我们需要创建样式表把标签的默认样式给清除掉

生成的css代码如下: 下面我们定义一下全局的字体,字号,行距等,点击css样式面板上的新建按钮,在弹出的窗口中选择器类型选择标签,名称选择body,然后在css编辑器中设置如下图所示属性 body全局样式定义后,下面我们给#menu定义一个灰色的1px边框及宽度,然后把li定义下背景色和下边框及内边距等 接下来定义li的背景色为浅灰色及下边框和内边距 这些属性设置完后,一个简单的纵向列表菜单初具模型了。因为导航菜单,需要链接到其它页面,下边把这些导航加上链接,然后在定义a的状态和鼠标划过状态。 要添加链接,先选择要添加链接的文字,然后在属性页面链接上输入要链接的页面址,我这里输入个#,是个虚拟链接,不指向任何页面。

构建BBS论坛系统项目中后台管理页面中的树形菜单的应用示例

1.1构建BBS论坛系统项目中后台管理页面中的树形菜单的应用示例1.1.1应用XTree树型控件在页面中实现树形菜单 1、应用XTree树型控件 (1)XTree树型控件 xtree.js是Web开发中运用较多的一个树型控件。其入门简单,功能强大,很多人在它的基础上开发出了自己的树型控件。 XloadTree也是https://www.sodocs.net/doc/c516733814.html,/公司的基于JavaScript的建立树型目录的开源产品,扩展性强,使用简单。由于XloadTree是基于XmlHttp请求/响应模型,必须使用http协议访问代码才可以正确加载XML文件。 (2)下载XTree树型控件(编程方式的系统包) https://www.sodocs.net/doc/c516733814.html,/ https://www.sodocs.net/doc/c516733814.html,/download/xtree117.zip

(3)下载XTree树型控件(XML文件方式的系统包、而且该XML文件可以是动态创建)https://www.sodocs.net/doc/c516733814.html,/dhtml/xloadtree/xloadtree.html

2、xtree有两种使用模式 其一为显示构造树,而其二为运用XML数据源,同时该XML数据源也可以动态在Servlet 组件中创建。 3、显示构造树(可以参考systemManage/contentPage/leftMenu.jsp) (1)第一步需要引用其样式单文件 (2)第二步再引用 xtree.js 文件 (3)第三步编程WebFXTreeItem以产生出菜单 var treeRoot = new WebFXTree('蓝梦BBS论坛后台管理菜单'); var tree_userInfoManaeFolder = new WebFXTreeItem("用户信息管理") var forwardQueryUserInfoItem=new WebFXTreeItem("查询一般用户信息"); forwardQueryUserInfoItem.action=''; forwardQueryUserInfoItem.target="mainFrame"; tree_userInfoManaeFolder.add(forwardQueryUserInfoItem); var forwardQueryVIPUserInfoItem=new WebFXTreeItem("查询VIP用户信息"); forwardQueryVIPUserInfoItem.action='

ABAP 树型菜单程序

ABAP 树型菜单程序 Jerry 项目中树型菜单很少用到,但是学会了,也是一种好事。最近,客户方就有一个要求,能够实现特殊的文档管理,包括动态的树型菜单。此文档中,我就介绍如何用ABAP创建一个简单的树型菜单!下面几个步骤只讲创建树型菜单几个重要的地方,最后面是详细的实现代码。建议学者粗略看看步骤,重点看最后的代码,然后自己学着按下面的DEMO写测试程序,直到成功为止,如有不懂的地方,可以到群内留言。或者文档有写得不好的地方,也可以提出来,我们一起加以改善! 一. 创建一个DIALOG屏幕(0900),创建一个定制控制: TREE_CONTAINER,作为一个容器来存放程序创建的 树型菜单,如下图所示: 二. 在屏幕PBO事件中,创建一个MOUDLE: m_init_tree,然后创建一个Subroutine: frm_init_tree。 在Subroutine中创建一个Object: g_application,g_application指向自己创建的一个Class:lcl_application。这个Class主要定义了一些事件,比如单击,双击,展开,链接单击等事件,用来注册及捕获树型菜单的父节点,子节点单击,双击,展开,链接单击等事件,然后在自己Class :lcl_application中相应自定义的Method中写相应的Code,实现特殊的操作。 三. 用程序创建一个容器类cl_gui_custom_container的实例g_custom_container,代码如下 CREATE OBJECT g_custom_container EXPORTING container_name = 'TREE_CONTAINER' EXCEPTIONS cntl_error = 1 cntl_system_error = 2 create_error = 3 lifetime_error = 4 lifetime_dynpro_dynpro_link = 5.

如何用DIV CSS制作横向表单

如何用DIV+CSS制作横向菜单?我们先来看一个菜单的例子,最终效果是: ?首页 ?产品介绍 ?服务介绍 ?技术支持 ?立刻购买 ?联系我们 然后我们来详细讲解步骤 第一步:建立一个无序列表 我们先建立一个无序列表,来建立菜单的结构。代码是:

效果是: ?首页 ?产品介绍 ?服务介绍 ?技术支持 ?立刻购买 ?联系我们 第二步:隐藏li的默认样式

因为看起来不是很好看,菜单通常都不需要li默认的圆点,我们给UL定义一个样式来消除这些圆点。 当然,为了更好的控制整个菜单,我们把菜单放在一个div里。页面代码变成:

CSS定义为: .test ul{list-style:none;} 说明:“.test ul”表示我要定义的样式将作用在test的层里的ul标签上。 现在的效果是没有圆点了: ?首页 ?产品介绍 ?服务介绍 ?技术支持 ?立刻购买 ?联系我们 第三步:关键的浮动 这里是菜单变成横向的关键,我们给li元素加上一个“float:left;”属性,让每个li浮动在前面一个li的左面。 CSS定义为: .test li{float:left;} 效果是:

特效导航栏

特效导航栏