项目结构:

项目运行:

技术要点:

1.4.1 技术要点
在分析具体的实现代码之前,先介绍一下本例的几个技术要点。
1 .选项的动态创建与删除
document 对象的 createElement 方法可以用来创建一个 HTML 元素。创建好的元素可以通过
setAttribute 方法设置其属性。基于以上两点,创建一个选项可以封装的方法如下:
function createOption(value, text) {
var opt = document.createElement("option");  //创建一个 option 节点
opt.setAttribute("value", value); //设置 value
opt.appendChild(document.createTextNode(text)); //给节点加入文本信息
return opt;
}
当清除一个 select 列表的选项时,只需要重新设置选项的 length 属性为合适的值即可。本例中保留
列表的第 1 个选项,因此将传入的列表对象 length 属性赋值为 1。
function clearOptions(selNode) {
selNode.length = 1; //设置列表长度为 1,仅保留默认选项
selNode.options[0].selected = true; //选中默认选项
}
2 .修改上级列表时重新初始化所有下级列表
当多级菜单全部选定后,如果用户重新选择了第一级列表,需要将其所有的下级列表全部初始化。
为了实现这个需求,本例创建了一个全局变量 selArray,以数组形式由上到下存放各级菜单的 id。在需
要初始化某级列表的下级时,对数组进行遍历即可确认下级列表的 id。
3 .使用 JSON  格式传递选项数据
JSON(JavaScript Object Notation)是一种用 JavaScript 对象符号格式化文本的简单方法。由于其
方便人们阅读,易于机器解析和生成,所以主要被当作一种轻量级的数据交换格式来使用。JSON 主
要支持两种类型的数据结构:“名称/值”对集合和有序值列表。下面详细介绍一下 JSON 支持的数据
元素。
-- 值:可以是双引号引起来的字符串(string)、数字(number)、布尔值、对象、数组等。示
例如下:
"Hello"
2006
true
-- 名称/值对:名称是一个字符串,后面跟一个“:”,接着就应是这个名称对应的值,每个“名
称/值”对以一个“,”分隔。示例如下:
图 1.10 实例运行效果

"Hello":"你好",
"Year":2006,
"isRight":true
-- 对象:以“{”开始,“}”结束,是一个无序的“名称/值”对集合。示例如下:
{
"Hello":"你好",
"Year":2006,
"isRight":true
}
-- 数组:以“[”开始,“]”结束,是值的有序集合,数组中的值以“,”分隔。示例如下:
[
"item1",
"item2",
"item3"
]
根据上面的介绍,发现利用“名称/值对”的形式可以方便地表示每一个 option 的内容。示例如下:
-- option 原始格式
<select>
<option value="B11">列表 B 选项 11</option>
<option value="B12">列表 B 选项 12</option>
<option value="B13">列表 B 选项 13</option>
</select>
-- JSON 格式
{
'B11':'列表 B 选项 11',
'B12':'列表 B 选项 12',
'B13':'列表 B 选项 13'
}
可以看到,使用 JSON 格式表示选项数据简洁明了,容易理解,非常适合用来进行数据交换。

数据库:

/*
SQLyog Ultimate v12.09 (64 bit)
MySQL - 5.5.53 : Database - ajaxexample_4
*********************************************************************
*/ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`ajaxexample_4` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `ajaxexample_4`; /*Table structure for table `menu` */ DROP TABLE IF EXISTS `menu`; CREATE TABLE `menu` (
`id` varchar(255) NOT NULL COMMENT '主键',
`text` varchar(255) NOT NULL COMMENT '显示内容',
`pid` varchar(255) NOT NULL DEFAULT '0' COMMENT '父id',
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `menu` */ insert into `menu`(`id`,`text`,`pid`,`sort`) values ('A1','A1','0',0),('A2','A2','0',0),('A3','A3','0',0),('B1','B1','A1',0),('B2','B2','A1',0),('B3','B3','A1',0),('B4','B4','A2',0),('B5','B5','A2',0),('B6','B6','A2',0),('B7','B7','A3',0),('B8','B8','A3',0),('C1','C1','B1',0),('C2','C2','B1',0),('C3','C3','B2',0),('C4','C4','B3',0),('C5','C5','B4',0),('C6','C6','B4',0); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

GetOptionServlet.java:

package com.gordon.servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.gordon.util.DBUtils; /**
* Servlet implementation class GetOptionsServlet
*/
@WebServlet("/GetOptionsServlet")
public class GetOptionsServlet extends HttpServlet {
private static final long serialVersionUID = 1L; /**
* @see HttpServlet#HttpServlet()
*/
public GetOptionsServlet() {
super();
// TODO Auto-generated constructor stub
} /**
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
} /**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { request.setCharacterEncoding("UTF-8");
response.setContentType("text/text; charset=UTF-8;"); String selectedId = request.getParameter("selectedId"); // 获取 selectedId
// 参数
int counter = 0; // 计数器
StringBuffer opts = new StringBuffer("{"); // 保存选项信息
// 定义查询数据库的 SQL 语句 String sql = "select * from menu where pid = ? order by sort asc";
Connection conn = null; // 声明 Connection 对象
PreparedStatement pstmt = null; // 声明 PreparedStatement 对象
ResultSet rs = null; // 声明 ResultSet 对象
try {
conn = DBUtils.getConnection(); // 获取数据库连接
pstmt = conn.prepareStatement(sql); // 根据 sql 创建 PreparedStatement
pstmt.setString(1, selectedId); // 设置参数
rs = pstmt.executeQuery(); // 执行查询,返回结果集
while (rs.next()) { // 遍历结果集
// 如果不是第一项,追加一个“,”用于分隔选项
if (counter > 0) {
opts.append(",");
}
opts.append("'");
opts.append(rs.getString("id")); opts.append("':'");
opts.append(rs.getString("text"));
opts.append("'");
counter++; // 计数器加 1
}
} catch (SQLException e) {
System.out.println(e.toString());
} catch (ClassNotFoundException cnfe) {
System.out.println(cnfe.toString());
} try {
rs.close(); // 关闭结果集
pstmt.close(); // 关闭 PreparedStatement
conn.close(); // 关闭连接
} catch (Exception e) {
System.out.println(e.getMessage());
} opts.append("}"); response.getWriter().print(opts.toString()); } /**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
} }

DBUtils.java

package com.gordon.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException; public class DBUtils {
private static final String URL = "jdbc:mysql://localhost:3306/ajaxexample_4";
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String USERNAME = "root";
private static final String PASSWORD = "root"; public static Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName(DRIVER);
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
}

select.js

var xmlHttp; // 用于保存 XMLHttpRequest 对象的全局变量
var targetSelId; // 用于保存要更新选项的列表 id
var selArray; // 用于保存级联菜单 id 的数组 //初始化列表数组(按等级)
function initSelArray() {
selArray = arguments; // arguments 对象包含了传入的所有参数
} // 用于创建 XMLHttpRequest 对象
function createXmlHttp() {
// 根据 window.XMLHttpRequest 对象是否存在使用不同的创建方式
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest(); // FireFox、Opera 等浏览器支持的创建方式
} else {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // IE 浏览器支持的创建方式
}
} // 获取列表选项的调用函数
function buildSelect(selectedId, targetId) {
if (selectedId == "") { // selectedId 为空串表示选中了默认项
clearSubSel(targetId); // 清除目标列表及下级列表中的选项
return; // 直接结束调用,不必向服务器请求信息
}
targetSelId = targetId; // 将传入的目标列表 id 赋值给 targetSelId 变量
createXmlHttp(); // 创建 XmlHttpRequest 对象
xmlHttp.onreadystatechange = buildSelectCallBack; // 设置回调函数
xmlHttp.open("GET", "GetOptionsServlet?selectedId=" + selectedId, true);
xmlHttp.send(null);
} //根据传入的 value 和 text 创建选项
function createOption(value, text) {
var opt = document.createElement("option"); // 创建一个 option 节点
opt.setAttribute("value", value); // 设置 value
opt.appendChild(document.createTextNode(text)); // 给节点加入文本信息
return opt;
} // 获取列表选项的回调函数
function buildSelectCallBack() {
if (xmlHttp.readyState == 4) {
// 将从服务器获得的文本转为对象直接量
var optionsInfo = eval("(" + xmlHttp.responseText + ")");
var targetSelNode = document.getElementById(targetSelId);
clearSubSel(targetSelId); // 清除目标列表及下级列表中的选项
// 遍历对象直接量中的成员
for ( var o in optionsInfo) {
// 在目标列表追加新的选项
targetSelNode.appendChild(createOption(o, optionsInfo[o]));
}
}
} //清除传入的列表节点内所有选项
function clearOptions(selNode) {
selNode.length = 1; // 设置列表长度为 1,仅保留默认选项
selNode.options[0].selected = true; // 选中默认选项
} // 清除下级子列表选项
function clearSubSel(targetId) {
var canClear = false; // 设置清除开关,初始值为假
for (var i = 0; i < selArray.length; i++) { // 遍历列表数组
if (selArray[i] == targetId) { // 当遍历至目标列表时,打开清除开关
canClear = true;
}
if (canClear) { // 从目标列表开始到最下级列表结束,开关始终保持打开
clearOptions(document.getElementById(selArray[i])); // 清除该级列表选项
}
}
}

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>多级联动菜单</title>
<script type="text/javascript" src="js/select.js"></script>
</head>
<!-- 页面加载完毕做两件事:1.初始化列表数组 2.为第 1 个列表赋值 -->
<body onload="initSelArray('selA','selB','selC');buildSelect('0', 'selA')">
<h1>多级联动菜单</h1>
<table>
<tr>
<td>列表 A</td>
<td><select name="selA" id="selA" onchange="buildSelect(this.value, 'selB')">
<option value="" selected>------请选择------</option>
</select></td>
</tr>
<tr>
<td>列表 B</td>
<td><select name="selB" id="selB" onchange="buildSelect(this.value, 'selC')">
<option value="" selected>------请选择------</option>
</select></td>
</tr>
<tr>
<td>列表 C</td>
<td><select name="selC" id="selC">
<option value="" selected>------请选择------</option>
</select></td>
</tr>
</table>
</body>
</html>

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

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

Ajax-ajax实例4-多级联动菜单的更多相关文章

  1. [ PHP+jQuery ] ajax 多级联动菜单的应用:电商网站的用户地址选择功能 ( 二 ) - 仿亚马逊下拉面板

    /** jQuery version: 1.8.3 Author: 小dee Date: 2014.11.8 */ 接上一篇博客. 实现带缓存的仿亚马逊下拉面板 效果图: 图1 初始 图2 点击省份 ...

  2. jQuery插件——多级联动菜单

    jQuery插件——多级联动菜单 引言 开发中,有好多地方用到联动菜单,以前每次遇到联动菜单的时候都去重新写,代码重用率很低,前几天又遇到联动菜单的问题,总结了下,发现可以开发一个联动菜单的功能,以后 ...

  3. 开发一个jQuery插件——多级联动菜单

    引言 开发中,有好多地方用到联动菜单,以前每次遇到联动菜单的时候都去重新写,代码重用率很低,前几天又遇到联动菜单的问题,总结了下,发现可以开发一个联动菜单的功能,以后想用的时候就方便多了.项目中每个页 ...

  4. jQuery cxSelect 多级联动下拉菜单

    随着电商热门,这种多层次的互动更充分地体现在下拉菜单,最明显的是多级联动地址下拉选择,因此,这里是一个简单的分享 jQuery cxSelect 多级联动下拉菜单 cxSelect 它是基于 jQue ...

  5. AngularJS中实现无限级联动菜单

    多级联动菜单是常见的前端组件,比如省份-城市联动.高校-学院-专业联动等等.场景虽然常见,但仔细分析起来要实现一个通用的无限分级联动菜单却不一定像想象的那么简单.比如,我们需要考虑子菜单的加载是同步的 ...

  6. 基于jQuery的AJAX实现三级联动菜单

    最近学习jQuery,所以就写了一个关于中国省市县/区的三级联动菜单,权当相互学习,相互促进,特此记录. 下面是嵌套js的html文件: <!DOCTYPE html> <html ...

  7. 多级联动系列——ajax调用XML实现三级联动

    ajax 使用起来特别的方便,再也不操心浏览器兼容问题了.用ajax调用XML页面中的内容,来生成三级联动,OK废话不多说,跟着我一步步写吧. 首先写一个XML文件.data.xml <?xml ...

  8. Ajax实现动态的二级级联菜单

    今天花了点时间用Ajax实现了一个二级级联菜单.整理总结一下.为了把重点放在Ajax和级联菜单的实现上,本文省略了数据库建表语句和操作数据库的代码! 数据库建表语句就不帖出来了.主要有两张表,区域表: ...

  9. JavaScript 多级联动浮动(下拉)菜单 (第二版)

    JavaScript 多级联动浮动(下拉)菜单 (第二版)   上一个版本(第一版请看这里)基本实现了多级联动和浮动菜单的功能,但效果不是太好,使用麻烦还有些bug,实用性不高.这次除了修改已发现的问 ...

随机推荐

  1. 利用HttpWebRequest模拟表单提交 JQuery 的一个轻量级 Guid 字符串拓展插件. 轻量级Config文件AppSettings节点编辑帮助类

    利用HttpWebRequest模拟表单提交   1 using System; 2 using System.Collections.Specialized; 3 using System.IO; ...

  2. 实时信号与sigqueue函数

    一.sigqueue函数 功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用. 原型:int sigqueue(pid_t pid, int s ...

  3. C 标准库IO缓冲区和内核缓冲区的区别

    1.C标准库的I/O缓冲区          UNIX的传统 是Everything is a file,键盘.显示器.串口.磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也 ...

  4. Python 字典 items() 方法

    描述 Python 字典 items() 方法以列表形式(并非直接的列表,若要返回列表值还需调用list函数)返回可遍历的(键, 值) 元组数组. 语法 items() 方法语法: D.items() ...

  5. 【转载】Gradle构建多模块项目

    本文转载自:https://yq.aliyun.com/articles/25589写的非常好! 改动如下: 1. 增加了一些[补充说明]. 2. 将执行命令使用较为显眼的博客园样式. 3. 将输出结 ...

  6. oracle各种常用管理sql及其他 ---待续

    启动客户端工具:sqlplus /nolog 使用sysdba链接:conn / as sysdba; select * from dba_users; --查看数据库里面所有用户,前提是你是有dba ...

  7. Spring Boot返回json数据及完美使用FastJson解析Json数据

     Spring Boot返回json数据 视频地址:http://www.iqiyi.com/w_19rubxzsr5.html 博文参考:https://blog.csdn.net/linxingl ...

  8. FAQ系列 | 如何保证主从复制数据一致性(转)

    导读 MySQL主从复制环境中,如何才能保证主从数据的一致性呢? 关于主从复制 现在常用的MySQL高可用方案,十有八九是基于 MySQL的主从复制(replication)来设计的,包括常规的一主一 ...

  9. 赶集mysql军规

    总是在灾难发生后,才想起容灾的重要性.总是在吃过亏后,才记得曾经有人提醒过. 一,核心军规 不在数据库做计算,cpu计算务必移至业务层 控制单表数据量,单表记录控制在千万级 控制列数量,字段数控制在2 ...

  10. tag标签数据库的设计

    方案一: 一个表,里面有个tags字段,存放以空格或逗号分隔的标签.缺点是长度受限,tag个数受限,查询like ‘%abc%’效率低 方案二: 同方案一,支持全文索引,或者用Lucence索引查询 ...