Ajax实现多级联动菜单

103 篇文章 2 订阅
79 篇文章 0 订阅

  最近在重温Ajax技术,就顺手拿起了当年的《Ajax经典案例开发大全》来温习。发现里面有些错误,现在就指出来,这样可以帮助后学者少走弯路。主要的技术有:MySql、JDBC、JSON、Ajax、JSP。其实本文不算原创,主要内容还是摘自《Ajax经典案例开发大全》。

        1.数据库设计

[sql] view plaincopyprint?

drop database if exists mydb;
create database mydb character set gbk;

--多级联动菜单
use mydb;
drop table if exists select_menu;
create table select_menu(
 id varchar(255) not null default '',
 text varchar(255) not null,
 pid varchar(255) not null,
 seq int(11) not null default 0,
 primary key (id)
)ENGINE=InnoDB DEFAULT CHARSET=gbk;

insert into select_menu values('A1','列表A选项1','INIT',1);
insert into select_menu values('A2','列表A选项2','INIT',2);
insert into select_menu values('B11','列表B选项11','A1',1);
insert into select_menu values('B12','列表B选项12','A1',2);
insert into select_menu values('B13','列表B选项13','A1',3);
insert into select_menu values('B21','列表B选项21','A2',1);
insert into select_menu values('B22','列表B选项22','A2',2);
insert into select_menu values('C111','列表C选项111','B11',1);
insert into select_menu values('C112','列表C选项112','B11',2);
insert into select_menu values('C121','列表C选项121','B12',1);
insert into select_menu values('C122','列表C选项122','B12',2);
insert into select_menu values('C131','列表C选项131','B13',1);
insert into select_menu values('C132','列表C选项132','B13',2);
insert into select_menu values('C211','列表C选项211','B21',1);
insert into select_menu values('C212','列表C选项212','B21',2);
insert into select_menu values('C221','列表C选项221','B22',1);
insert into select_menu values('C222','列表C选项222','B22',2);
 

        2.连接数据库的工具类

[java] view plaincopyprint?

package com.lanp.ajax.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 连接数据库的工具类,被定义成不可继承且是私有访问
 * @author lanp
 * @since 2012-2-29 22:27
 */
public final class DBUtils {
 private static String url = "jdbc:mysql://localhost:3306/mydb?characterEncoding=gbk";
 private static String user = "root";
 private static String psw = "root";
 
 private static  Connection conn;
 
 static {
  try {
   Class.forName("com.mysql.jdbc.Driver");
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
   throw new RuntimeException(e);
  }
 }
 
 private DBUtils() {
  
 }
 
 /**
  * 获取数据库的连接
  * @return conn
  */
 public static Connection getConnection() {
  try {
   conn = DriverManager.getConnection(url, user, psw);
  } catch (SQLException e) {
   e.printStackTrace();
   throw new RuntimeException(e);
  }
  return conn;
 }
 
 /**
  * 释放资源
  * @param conn
  * @param pstmt
  * @param rs
  */
 public static void closeResources(Connection conn,PreparedStatement pstmt,ResultSet rs) {
  if(null != rs) {
   try {
    rs.close();
   } catch (SQLException e) {
    e.printStackTrace();
    throw new RuntimeException(e);
   } finally {
    if(null != pstmt) {
     try {
      pstmt.close();
     } catch (SQLException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
     } finally {
      if(null != conn) {
       try {
        conn.close();
       } catch (SQLException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
       }
      }
     }
    }
   }
  }
 }
}

 

        3.select_menu.html页面

[html] view plaincopyprint?

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>多级联动菜单</title>

 <script type="text/javascript">
  var xmlHttp;     //用于保存XMLHttpRequest对象的全局变量
  var targetSelId;    //用于保存要更新选项的列表ID 
  var selArray = new Array();  //用于保存级联菜单ID的数组,《Ajax经典案例开发大全》中没有= new Array()代码
  
  //用于创建XMLHttpRequest对象
  function createXmlHttp() {
   if(window.XMLHttpRequest) {
    xmlHttp = new XMLHttpRequest();
   } else {
    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
   }
  }
  
  //获取列表选项的调用函数
  function buildSelect(selectedId,targetId) {
   if("" == selectedId) {   //selectedId为空串表示选中了默认项
    clearSubSel(targetId);  //清楚目标列表及下级列表中的值
    return;      //直接结束调用,不必向服务器请求信息
   }
   
   targetSelId = targetId;   //将传入的目标列表ID赋值给targetSelId变量
   createXmlHttp();    //创建XMLHttpRequest对象
   xmlHttp.onreadystatechange = buildSelectCallBack;  //设置回调函数
   xmlHttp.open("GET", "select_menu.jsp?selectedId="+selectedId, true);
   xmlHttp.send(null);
  }
  
  //获取列表选项的回调函数
  function buildSelectCallBack() {
   if(4 == xmlHttp.readyState) {
    //将从服务器获得的文本转为对象直接量
    var optionsInfo = eval("(" + xmlHttp.responseText + ")");
    var targetSelNode = document.getElementById(targetSelId);
    clearSubSel(targetSelId);
    //遍历对象直接量中的成员
    for(var o in optionsInfo) {
     //在目标列表追加新的选项
     targetSelNode.appendChild(createOption(o,optionsInfo[o]));
    }
   }
  }
  
  //根据传入的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 clearOptions(selNode) {
   selNode.options.length = 1;
   selNode.options[0].selected = true;
  }
  
  //初始化列表数组,《Ajax经典案例开发大全》中该方法的代码是有误没有实现真正的初始化
  function initSelArray(selA,selB,selC) {
   selArray[0] = selA;
   selArray[1] = selB;
   selArray[2] = selC;
  }
  
  //清除下级子列表选项
  function clearSubSel(targetId) {
   var len = selArray.length;
   for(var i=0;i<len;i++) {
    var j = 0;
    if(selArray[i] == targetId) {
     j = i;
     break;
    }
   }
   for(; j<len; j++) {
    clearOptions(document.getElementById(selArray[j]));
   }
   //《Ajax经典案例开发大全》中该方法的代码是有误,不能实现下级列表全部清除功能,且代码冗余,如下示:
   //var canClear = false;
   //for(var i=0; i<selArray.length; i++) {
   // if(selArray[i] == targetId) {
   //  canClear = true;
   // }
   // if(canClear) {
   //  clearOptions(document.getElementById(selArray[i]));
   // }
   //}
  }
 </script>
</head>
<!-- 页面加载完毕做2件事:1.初始化列表数组,2.为第一个列表赋值 -->
<body οnlοad="initSelArray('selA','selB','selC');buildSelect('INIT','selA')">
 <h1>多级联动菜单</h1>
 <table>
  <tr>
   <td>列表A</td>
   <td>
    <select name="selA" id="selA" οnchange="buildSelect(this.value,'selB')">
     <option value="" selected>-------请选择-------</option>
    </select>
   </td>
  </tr>
  
  <tr>
   <td>列表B</td>
   <td>
    <select name="selB" id="selB" οnchange="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>
 

        4.select_menu.jsp后台服务

[html] view plaincopyprint?
 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.sql.*,com.lanp.ajax.db.DBUtils" %>   
<%!
 //访问数据库取得下级选项信息
 String getOptions(String selectedId) {
  int counter = 0;
  StringBuffer opts = new StringBuffer("{");
  String sql = "select * from select_menu where pid=? order by seq asc";
  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
   conn = DBUtils.getConnection();
   pstmt = conn.prepareStatement(sql);
   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++;
   }
  } catch(SQLException e) {
   System.out.println(e.toString());
  } finally {
   DBUtils.closeResources(conn,pstmt,rs);
  }
  opts.append("}");
  System.out.println(opts.toString());
  return opts.toString();
 }
%>

<%
 out.clear();
 String selectedId = request.getParameter("selectedId");
 String optionsInfo = getOptions(selectedId);
 out.print(optionsInfo);
%>
OK,TKS!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值