项目结构:

项目演示:

技术要点:

1.3.2 技术要点
在基本原理的介绍中,了解到通过在父节点内动态创建子节点,并利用样式表缩进完成树形列表
的基本框架。除了这一点外,还有下面一些问题需要考虑。
1 .将父节点所有的子节点放入一个容器中
基本原理页面中仅包含了创建子节点的功能,不可以将创建好的节点再进行关闭操作。实际应用
中菜单总是包含打开和关闭两种操作。为了方便进行关闭操作,将子节点放入一个容器中,在关闭时
只需要设置容器的显示属性即可。
2 .节点开关的具体实现
每个父节点的所有子节点放入容器中后,在单击父节点时判断子节点容器的显示状态。如果当前
为打开状态,则将其关闭,反之则将其打开。具体使用的方法是调用节点的 style.display 属性进行判断,
关闭时的状态为 none,非 none 时表示打开。为了清晰地表示父节点的打开或关闭状态,使用“+”和
“-”字符进行标识。
3 .节点分为目录节点和非目录节点
目录节点下可包含子节点,非目录节点也可称为叶子节点,即该节点不包含子节点。在本例中对
这两种节点进行区别对待。单击目录节点将对其子节点进行展开或关闭操作。单击非目录节点将链接
到新的页面(目前暂时将新页面地址弹出,在实际应用中可进行修改)。

数据库:

  1. /*
  2. SQLyog Ultimate v12.09 (64 bit)
  3. MySQL - 5.5.53 : Database - ajaxexample_3
  4. *********************************************************************
  5. */
  6.  
  7. /*!40101 SET NAMES utf8 */;
  8.  
  9. /*!40101 SET SQL_MODE=''*/;
  10.  
  11. /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
  12. /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
  13. /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
  14. /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
  15. CREATE DATABASE /*!32312 IF NOT EXISTS*/`ajaxexample_3` /*!40100 DEFAULT CHARACTER SET utf8 */;
  16.  
  17. USE `ajaxexample_3`;
  18.  
  19. /*Table structure for table `tree` */
  20.  
  21. DROP TABLE IF EXISTS `tree`;
  22.  
  23. CREATE TABLE `tree` (
  24. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  25. `text` varchar(255) NOT NULL COMMENT '显示文本',
  26. `isfolder` varchar(5) NOT NULL DEFAULT 'false' COMMENT '是否含有下级目录',
  27. `link` varchar(255) NOT NULL COMMENT '连接',
  28. `pid` int(11) NOT NULL DEFAULT '0' COMMENT '父id',
  29. PRIMARY KEY (`id`)
  30. ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
  31.  
  32. /*Data for the table `tree` */
  33.  
  34. insert into `tree`(`id`,`text`,`isfolder`,`link`,`pid`) values (1,'目录1','true','',0),(2,'目录2','true','',0),(3,'目录3','true','',0),(4,'目录1-1','true','',1),(5,'目录1-2','true','',1),(6,'目录1-3','true','',1),(7,'目录2-1','true','',2),(8,'项目1','false','https://www.baidu.com',2),(9,'项目1','false','https://www.baidu.com',0),(10,'项目2','false','https://www.baidu.com',0);
  35.  
  36. /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
  37. /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
  38. /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
  39. /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

GetTreeByParentId.java:获取节点信息servlet:

  1. package com.gordon.servlet;
  2.  
  3. import java.io.IOException;
  4. import java.sql.Connection;
  5. import java.sql.PreparedStatement;
  6. import java.sql.ResultSet;
  7. import java.sql.SQLException;
  8.  
  9. import javax.servlet.Servlet;
  10. import javax.servlet.ServletConfig;
  11. import javax.servlet.ServletException;
  12. import javax.servlet.annotation.WebServlet;
  13. import javax.servlet.http.HttpServlet;
  14. import javax.servlet.http.HttpServletRequest;
  15. import javax.servlet.http.HttpServletResponse;
  16.  
  17. import com.gordon.util.DBUtils;
  18.  
  19. /**
  20. * Servlet implementation class GetTreeByParentId
  21. */
  22. @WebServlet("/GetTreeByParentId")
  23. public class GetTreeByParentId extends HttpServlet {
  24. private static final long serialVersionUID = 1L;
  25.  
  26. /**
  27. * @see HttpServlet#HttpServlet()
  28. */
  29. public GetTreeByParentId() {
  30. super();
  31. // TODO Auto-generated constructor stub
  32. }
  33.  
  34. /**
  35. * @see Servlet#init(ServletConfig)
  36. */
  37. public void init(ServletConfig config) throws ServletException {
  38. // TODO Auto-generated method stub
  39. }
  40.  
  41. /**
  42. * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
  43. * response)
  44. */
  45. protected void doGet(HttpServletRequest request, HttpServletResponse response)
  46. throws ServletException, IOException {
  47.  
  48. request.setCharacterEncoding("utf-8");
  49. response.setContentType("text/xml;charset=utf-8");
  50.  
  51. String parentId = request.getParameter("parentId"); // 获取要加载的节点编号
  52. // 创建用于保存 xmlTree 信息的 StringBuffer 对象
  53. StringBuffer xmlTree = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  54. xmlTree.append("<tree>"); // xmlTree 根节点为<tree>
  55. /*
  56. * 根据请求的目标节点返回不同的结果 isFolder 属性标识当前节点是否为目录,true 表示目录,false 表示普通节点 link
  57. * 属性用于设置普通节点的目标链接地址
  58. */
  59. String sql = "select * from tree where pid = ?"; // 定义查询数据库的 SQL 语句
  60. Connection conn = null; // 声明 Connection 对象
  61. PreparedStatement pstmt = null; // 声明 PreparedStatement 对象
  62. ResultSet rs = null; // 声明 ResultSet 对象
  63. try {
  64. conn = DBUtils.getConnection(); // 获取数据库连接
  65. pstmt = conn.prepareStatement(sql); // 创建 PreparedStatement
  66. pstmt.setString(1, parentId); // 设置参数
  67. rs = pstmt.executeQuery(); // 执行查询,返回结果集
  68. while (rs.next()) { // 遍历结果集创建 item 节点
  69. xmlTree.append("<item id=\"");
  70. xmlTree.append(rs.getString("id"));
  71. xmlTree.append("\" isFolder=\"");
  72. xmlTree.append(rs.getString("isfolder"));
  73. String link = rs.getString("link");
  74. // 当 link 字段数据存在时才加入 link 属性信息
  75. if (link != null && !"".equals(link)) {
  76. xmlTree.append("\" link=\"");
  77. xmlTree.append(link);
  78. }
  79. xmlTree.append("\">");
  80. xmlTree.append(rs.getString("text"));
  81. xmlTree.append("</item>");
  82. }
  83. } catch (ClassNotFoundException cnfe) {
  84. System.out.println(cnfe.toString());
  85. } catch (SQLException e) {
  86. System.out.println(e.toString());
  87. }
  88.  
  89. try {
  90. rs.close(); // 关闭结果集
  91. pstmt.close(); // 关闭 PreparedStatement
  92. conn.close(); // 关闭连接
  93. } catch (Exception e) {
  94. System.out.println(e.toString());
  95. }
  96.  
  97. xmlTree.append("</tree>"); // xmlTree 根节点的结束标签
  98.  
  99. System.out.println(xmlTree.toString());
  100.  
  101. response.getWriter().print(xmlTree.toString());
  102. }
  103.  
  104. /**
  105. * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
  106. * response)
  107. */
  108. protected void doPost(HttpServletRequest request, HttpServletResponse response)
  109. throws ServletException, IOException {
  110. // TODO Auto-generated method stub
  111. doGet(request, response);
  112. }
  113.  
  114. }

DBUtil.java:数据库连接:

  1. package com.gordon.util;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.DriverManager;
  5. import java.sql.SQLException;
  6.  
  7. public class DBUtils {
  8. private static final String URL = "jdbc:mysql://localhost:3306/ajaxexample_3";
  9. private static final String DRIVER = "com.mysql.jdbc.Driver";
  10. private static final String USERNAME = "root";
  11. private static final String PASSWORD = "root";
  12.  
  13. public static Connection getConnection() throws ClassNotFoundException, SQLException {
  14. Class.forName(DRIVER);
  15. return DriverManager.getConnection(URL, USERNAME, PASSWORD);
  16. }
  17. }

tree.css:

  1. /* 子节点容器 box 需要缩进 */
  2. div.box {
  3. margin-left: 20px;
  4. }
  5. /* 目录节点标识样式 */
  6. span.folderMark {
  7. font-family: "宋体";
  8. color: #F00;
  9. cursor: hand;
  10. margin-right: 5px;
  11. }
  12. /* 目录节点样式 */
  13. span.folder {
  14. cursor: hand;
  15. }
  16. /* 非目录节点标识样式 */
  17. span.itemMark {
  18. font-family: "宋体";
  19. color: #F00;
  20. margin-right: 5px;
  21. }
  22. /* 非目录节点样式 */
  23. span.item {
  24. cursor: hand;
  25. }

tree.js:

  1. // 创建Tree对象
  2. var Tree = new function() {
  3. this._url = "GetTreeByParentId"; // 用于请求数据的服务器页面地址
  4.  
  5. this._openMark = "-"; // 目录节点处于展开状态时的标识
  6. this._closeMark = "+"; // 目录节点处于关闭状态时的标识
  7. this._itemMark = "·"; // 非目录节点标识
  8.  
  9. this._initId = "treeInit"; // 树形目录初始 div 标识
  10. this._rootData = "根目录"; // 根节点文字信息
  11.  
  12. this._boxSuffix = "_childrenBox"; // 子节点容器后缀
  13.  
  14. this._folderType = "folder"; // 目录节点类型变量
  15. this._itemType = "item"; // 非目录节点类型变量
  16.  
  17. // 初始化根节点
  18. this.init = function() {
  19. var initNode = document.getElementById(this._initId); // 获取初始 div
  20. var _node = document.createElement("div"); // 创建新 div 作为根节点
  21.  
  22. _node.id = "0"; // 根节点 id 为 0
  23. _node.innerHTML = this.createItemHTML(_node.id, this._folderType,
  24. this._rootData);
  25. initNode.appendChild(_node); // 将根节点加入初始 div
  26. }
  27.  
  28. // 获取给定节点的子节点
  29. this.getChildren = function(_parentId) {
  30. // 获取页面子节点容器 box
  31. var childBox = document.getElementById(_parentId + this._boxSuffix);
  32. // 如果子节点容器已存在,则直接设置显示状态,否则从服务器获取子节点信息
  33. if (childBox) {
  34. var isHidden = (childBox.style.display == "none"); // 判断当前状态是否隐藏
  35. // 隐藏则显示,如果显示则变为隐藏
  36. childBox.style.display = isHidden ? "" : "none";
  37. // 根据子节点的显示状态修改父节点标识
  38. var _parentNode = document.getElementById(_parentId);
  39. _parentNode.firstChild.innerHTML = isHidden ? this._openMark
  40. : this._closeMark;
  41. } else {
  42. var xmlHttp = this.createXmlHttp(); // 创建 XmlHttpRequest 对象
  43. xmlHttp.onreadystatechange = function() {
  44. if (xmlHttp.readyState == 4) {
  45. // 调用 addChildren 函数生成子节点
  46. Tree.addChildren(_parentId, xmlHttp.responseXML);
  47. }
  48. }
  49. xmlHttp.open("GET", this._url + "?parentId=" + _parentId, true);
  50. xmlHttp.send(null);
  51. }
  52. }
  53.  
  54. // 根据获取的 xmlTree 信息,设置指定节点的子节点
  55. this.addChildren = function(_parentId, _data) {
  56. var _parentNode = document.getElementById(_parentId); // 获取父节点
  57. _parentNode.firstChild.innerHTML = this._openMark;// 设置节点前标记为目录展开形式
  58. // 创建一个容器,称为 box,用于存放所有子节点
  59. var _nodeBox = document.createElement("div");
  60. // 容器的 id 规则为:在父节点 id 后加固定后缀
  61. _nodeBox.id = _parentId + this._boxSuffix;
  62. _nodeBox.className = "box"; // 样式名称为 box,div.box 样式会对此节点生效
  63. _parentNode.appendChild(_nodeBox); // 将子节点 box 放入父节点中
  64. // 获取所有 item 节点
  65. var _children = _data.getElementsByTagName("tree")[0].childNodes;
  66.  
  67. var _child = null; // 声明_child 变量用于保存每个子节点
  68. var _childType = null; // 声明_childType 变量用于保存每个子节点类型
  69. for (var i = 0; i < _children.length; i++) { // 循环创建每个子节点
  70. _child = _children[i];
  71. _node = document.createElement("div"); // 每个节点对应一个新 div
  72. _node.id = _child.getAttribute("id"); // 节点的 id 值就是获取数据中的 id 属性值
  73. // 设置子节点类型
  74. _childType = _child.getAttribute("isFolder") == "true" ? this._folderType
  75. : this._itemType;
  76. // 根据节点类型不同,调用 createItemHTML 创建节点内容
  77. if (_childType == this._itemType) {
  78. // 非目录节点在最后多传一个 link 数据,用于单击后链接到新页面
  79. _node.innerHTML = this.createItemHTML(_node.id, _childType,
  80. _child.firstChild.data, _child.getAttribute("link"));
  81. } else {
  82. // 目录节点只需传递 id,节点类型,节点数据
  83. _node.innerHTML = this.createItemHTML(_node.id, _childType,
  84. _child.firstChild.data);
  85. }
  86. _nodeBox.appendChild(_node); // 将创建好的节点加入子节点 box 中
  87. }
  88. }
  89.  
  90. // 创建节点的页面片断
  91. this.createItemHTML = function(itemId, itemType, itemData, itemLink) {
  92. // 根据节点类型不同,返回不同的 HTML 片断
  93. if (itemType == this._itemType) {
  94. // 非目录节点的 class 属性以 item 开头,并且 onclick 事件调用 Tree.clickItem 函数
  95. return '<span class="itemMark">' + this._itemMark + '</span>'
  96. + '<span class="item" onclick="Tree.clickItem(\''
  97. + itemLink + '\');">' + itemData + '</span>';
  98. } else if (itemType == this._folderType) {
  99. // 目录节点的 class 属性以 folder 开头,并且 onclick 事件调用 Tree.getChildren 函数
  100. return '<span class="folderMark" onclick="Tree.getChildren(\''
  101. + itemId + '\')">' + this._closeMark + '</span>'
  102. + '<span class="folder" onclick="Tree.getChildren(\''
  103. + itemId + '\')">' + itemData + '</span>'
  104. }
  105. }
  106.  
  107. // 单击叶子节点后的动作,目前只是弹出对话框,可修改为链接到具体的页面
  108. this.clickItem = function(_link) {
  109. alert("当前节点可以链接到页面 " + _link + " 。");
  110. }
  111.  
  112. // 用于创建 XMLHttpRequest 对象
  113. this.createXmlHttp = function() {
  114. var xmlHttp = null;
  115. // 根据 window.XMLHttpRequest 对象是否存在使用不同的创建方式
  116. if (window.XMLHttpRequest) {
  117. xmlHttp = new XMLHttpRequest(); // FireFox、Opera 等浏览器支持的创建方式
  118. } else {
  119. xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // IE 浏览器支持的创建方式
  120. }
  121. return xmlHttp;
  122. }
  123. }

index.jsp:

  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>动态树形列表</title>
  6. <script type="text/javascript" src="js/tree.js"></script>
  7. <link href="css/tree.css" type="text/css" rel="stylesheet">
  8. </head>
  9. <body onload="Tree.init()">
  10. <h1>动态树形列表</h1>
  11. <div id="treeInit"></div>
  12. </body>
  13. </html>

+++++++++++++++++++++++++++

参考:ajax实用案例大全-1动态加载数据  https://wenku.baidu.com/view/c7897bf4700abb68a982fb91.html

Ajax-ajax实例3-动态树形列表的更多相关文章

  1. Winform开发主界面菜单的动态树形列表展示

    我在之前很多文章里面,介绍过Winform主界面的开发,基本上都是标准的界面,在顶部放置工具栏,中间区域则放置多文档的内容,但是在顶部菜单比较多的时候,就需要把菜单分为几级处理,如可以在顶部菜单放置一 ...

  2. PHP+Ajax点击加载更多列表数据实例

    一款简单实用的PHP+Ajax点击加载更多列表数据实例,实现原理:通过“更多”按钮向服务端发送Ajax请求,PHP根据分页参数查询将最新的几条记录,数据以JSON形式返回,前台Query解析JSON数 ...

  3. js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符

    js中对arry数组的各种操作小结   最近工作比较轻松,于是就花时间从头到尾的对js进行了详细的学习和复习,在看书的过程中,发现自己平时在做项目的过程中有很多地方想得不过全面,写的不够合理,所以说啊 ...

  4. AJAX 数据库实例

    AJAX 用于创建动态性更强的应用程序. AJAX ASP 实例 下面的例子将演示当用户在输入框中键入字符时,网页如何与服务器进行通信: 实例 请在下面的输入框中键入字母(A - Z): 姓名: 建议 ...

  5. ajax常用实例代码总结新手向参考(一)

    http的交互方法有四种:get.post.put(增加数据).delete(删除数据) put和delete实现用的是get和post   get方式 页面不能被修改,只是获取查询信息.但是提交的数 ...

  6. AJAX XML 实例

    AJAX XML 实例 下面的例子将演示网页如何使用 AJAX 来读取来自 XML 文件的信息 <!DOCTYPE html> <html> <head> < ...

  7. php中ajax使用实例

    php中ajax使用实例 一.总结 1.多复习:这两段代码都挺简单的,就是需要复习,要多看 2.ajax原理:ajax就是部分更新页面,其实还在的html页面监听到事件后,然后传给服务器进行操作,这里 ...

  8. thinkphp中ajax使用实例(thinkphp内置支持ajax)

    thinkphp中ajax使用实例(thinkphp内置支持ajax) 一.总结 1.thinkphp应该是内置支持ajax的,所以请求类型里面才会有是否是ajax // 是否为 Ajax 请求 if ...

  9. jquery动态添加列表后样式失效解决方式

    最近在做一个通讯录,使用jquery mobile方式来做,在动态添加列表后,listview原有的样式失效,折腾一会,找出解决办法.代码如下. <%@ page language=" ...

随机推荐

  1. linux创建新用户及权限

    在Linux中添加普通新用户 ,超级用户(也称为“root”)是一个具有修改系统中任何文件权力的特别账号.在日常工作中,最好不要使用超级用户账号进入系统,因为任何错误操作都可能导致巨大的损失.由于超级 ...

  2. python学习笔记011——内置函数sorted()

    1 描述 sorted() 函数对所有可迭代的对象进行排序操作. sorted() 与sort()函数之间的区别 1 排序对象 sorted:所有可迭代对象的排序 sort:list列表的排序 2 返 ...

  3. Linux时间子系统(十六) clockevent

    一.clock event控制的通用逻辑 1.产生clock event的设备 各种系统的timer硬件形形色色,不过在general clock event device layer,struct ...

  4. poj1564 Sum it up

    题目链接: http://poj.org/problem?id=1564 题目: Sum It Up Time Limit: 1000MS   Memory Limit: 10000K Total S ...

  5. UHF RFID编码之TPP编码

    GB/T 39768通信交互模型 读写器使用TPP对基带数据进行编码,使用DSB-ASK或者SSB-ASK方式调制射频载波,向一个或者多个标签发送命令.命令发送后,读写器继续发送未经调制的射频载波,并 ...

  6. STM32以太网ETH

    注:stm32F1系列中F103片上不含MAC控制器,所以不支持以太网,只有F105和F107才支持

  7. cocos2d-x解决中文乱码问题的几种办法

    昨天改写cocos2d-x的例程,想在其基础上加上一个计分系统.没有分数实在让人没有玩下去的动力! 我在主场景上加上了一个CCLabelTTF,用于显示分数. 但是意外的发现,当内容含有中文时,CCL ...

  8. Exception时信息的记录

    系统总有出现异常的时候,那么出现异常时应该如何处理? 一直以来,我都以为这么处理就足够的: 在日志中打印Exception的堆栈信息,以便排查原因 反馈给用户系统xxx出现问题 package com ...

  9. css实现遮罩层(解决透明背景上的文字不透明)

    .PopUp_layer{   position:fixed;   top: 0;   left: 0;   right:0;   bottom:0;   width:100%;   height:1 ...

  10. my.cnf 配置详解

    调整MySQL运行参数,修改/etc/my.cnf文件调整mysql运行参数重启MySQL后生效,在MySQL4版本以后,一部分内部变量可以在MySQL运行时设置,不过重启MySQL就失效了. mys ...