AJAX实现三级菜单联动

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

        1.数据库设计

[sql]  view plain  copy
 print ?
  1. drop database if exists mydb;  
  2. create database mydb character set gbk;  
  3.   
  4. --多级联动菜单  
  5. use mydb;  
  6. drop table if exists select_menu;  
  7. create table select_menu(  
  8.     id varchar(255) not null default '',  
  9.     text varchar(255) not null,  
  10.     pid varchar(255) not null,  
  11.     seq int(11) not null default 0,  
  12.     primary key (id)  
  13. )ENGINE=InnoDB DEFAULT CHARSET=gbk;  
  14.   
  15. insert into select_menu values('A1','列表A选项1','INIT',1);  
  16. insert into select_menu values('A2','列表A选项2','INIT',2);  
  17. insert into select_menu values('B11','列表B选项11','A1',1);  
  18. insert into select_menu values('B12','列表B选项12','A1',2);  
  19. insert into select_menu values('B13','列表B选项13','A1',3);  
  20. insert into select_menu values('B21','列表B选项21','A2',1);  
  21. insert into select_menu values('B22','列表B选项22','A2',2);  
  22. insert into select_menu values('C111','列表C选项111','B11',1);  
  23. insert into select_menu values('C112','列表C选项112','B11',2);  
  24. insert into select_menu values('C121','列表C选项121','B12',1);  
  25. insert into select_menu values('C122','列表C选项122','B12',2);  
  26. insert into select_menu values('C131','列表C选项131','B13',1);  
  27. insert into select_menu values('C132','列表C选项132','B13',2);  
  28. insert into select_menu values('C211','列表C选项211','B21',1);  
  29. insert into select_menu values('C212','列表C选项212','B21',2);  
  30. insert into select_menu values('C221','列表C选项221','B22',1);  
  31. insert into select_menu values('C222','列表C选项222','B22',2);  


 

        2.连接数据库的工具类

[java]  view plain  copy
 print ?
  1. package com.lanp.ajax.db;  
  2.   
  3. import java.sql.Connection;  
  4. import java.sql.DriverManager;  
  5. import java.sql.PreparedStatement;  
  6. import java.sql.ResultSet;  
  7. import java.sql.SQLException;  
  8.   
  9. /** 
  10.  * 连接数据库的工具类,被定义成不可继承且是私有访问 
  11.  * @author lanp 
  12.  * @since 2012-2-29 22:27 
  13.  */  
  14. public final class DBUtils {  
  15.     private static String url = "jdbc:mysql://localhost:3306/mydb?characterEncoding=gbk";  
  16.     private static String user = "root";  
  17.     private static String psw = "root";  
  18.       
  19.     private static  Connection conn;  
  20.       
  21.     static {  
  22.         try {  
  23.             Class.forName("com.mysql.jdbc.Driver");  
  24.         } catch (ClassNotFoundException e) {  
  25.             e.printStackTrace();  
  26.             throw new RuntimeException(e);  
  27.         }  
  28.     }  
  29.       
  30.     private DBUtils() {  
  31.           
  32.     }  
  33.       
  34.     /** 
  35.      * 获取数据库的连接 
  36.      * @return conn 
  37.      */  
  38.     public static Connection getConnection() {  
  39.         try {  
  40.             conn = DriverManager.getConnection(url, user, psw);  
  41.         } catch (SQLException e) {  
  42.             e.printStackTrace();  
  43.             throw new RuntimeException(e);  
  44.         }  
  45.         return conn;  
  46.     }  
  47.       
  48.     /** 
  49.      * 释放资源 
  50.      * @param conn 
  51.      * @param pstmt 
  52.      * @param rs 
  53.      */  
  54.     public static void closeResources(Connection conn,PreparedStatement pstmt,ResultSet rs) {  
  55.         if(null != rs) {  
  56.             try {  
  57.                 rs.close();  
  58.             } catch (SQLException e) {  
  59.                 e.printStackTrace();  
  60.                 throw new RuntimeException(e);  
  61.             } finally {  
  62.                 if(null != pstmt) {  
  63.                     try {  
  64.                         pstmt.close();  
  65.                     } catch (SQLException e) {  
  66.                         e.printStackTrace();  
  67.                         throw new RuntimeException(e);  
  68.                     } finally {  
  69.                         if(null != conn) {  
  70.                             try {  
  71.                                 conn.close();  
  72.                             } catch (SQLException e) {  
  73.                                 e.printStackTrace();  
  74.                                 throw new RuntimeException(e);  
  75.                             }  
  76.                         }  
  77.                     }  
  78.                 }  
  79.             }  
  80.         }  
  81.     }  
  82. }  


 

        3.select_menu.html页面

[html]  view plain  copy
 print ?
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  2. <html>  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  5. <title>多级联动菜单</title>  
  6.   
  7.     <script type="text/javascript">  
  8.         var xmlHttp;                    //用于保存XMLHttpRequest对象的全局变量  
  9.         var targetSelId;                //用于保存要更新选项的列表ID      
  10.         var selArray = new Array();     //用于保存级联菜单ID的数组,《Ajax经典案例开发大全》中没有= new Array()代码  
  11.           
  12.         //用于创建XMLHttpRequest对象  
  13.         function createXmlHttp() {  
  14.             if(window.XMLHttpRequest) {  
  15.                 xmlHttp = new XMLHttpRequest();  
  16.             } else {  
  17.                 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");  
  18.             }  
  19.         }  
  20.           
  21.         //获取列表选项的调用函数  
  22.         function buildSelect(selectedId,targetId) {  
  23.             if("" == selectedId) {          //selectedId为空串表示选中了默认项  
  24.                 clearSubSel(targetId);      //清楚目标列表及下级列表中的值  
  25.                 return;                     //直接结束调用,不必向服务器请求信息  
  26.             }  
  27.               
  28.             targetSelId = targetId;         //将传入的目标列表ID赋值给targetSelId变量  
  29.             createXmlHttp();                //创建XMLHttpRequest对象  
  30.             xmlHttp.onreadystatechange = buildSelectCallBack;       //设置回调函数  
  31.             xmlHttp.open("GET", "select_menu.jsp?selectedId="+selectedId, true);  
  32.             xmlHttp.send(null);  
  33.         }  
  34.           
  35.         //获取列表选项的回调函数  
  36.         function buildSelectCallBack() {  
  37.             if(4 == xmlHttp.readyState) {  
  38.                 //将从服务器获得的文本转为对象直接量  
  39.                 var optionsInfo = eval("(" + xmlHttp.responseText + ")");  
  40.                 var targetSelNode = document.getElementById(targetSelId);  
  41.                 clearSubSel(targetSelId);  
  42.                 //遍历对象直接量中的成员  
  43.                 for(var o in optionsInfo) {  
  44.                     //在目标列表追加新的选项  
  45.                     targetSelNode.appendChild(createOption(o,optionsInfo[o]));  
  46.                 }  
  47.             }  
  48.         }  
  49.           
  50.         //根据传入的value和text创建选项  
  51.         function createOption(value,text) {  
  52.             var opt = document.createElement("option");         //创建一个option节点  
  53.             opt.setAttribute("value", value);                   //设置value  
  54.             opt.appendChild(document.createTextNode(text));     //给节点加入文本信息  
  55.             return opt;  
  56.         }  
  57.           
  58.         //清除传入的列表节点内所有选项  
  59.         function clearOptions(selNode) {  
  60.             selNode.options.length = 1;  
  61.             selNode.options[0].selected = true;  
  62.         }  
  63.           
  64.         //初始化列表数组,《Ajax经典案例开发大全》中该方法的代码是有误没有实现真正的初始化  
  65.         function initSelArray(selA,selB,selC) {  
  66.             selArray[0] = selA;  
  67.             selArray[1] = selB;  
  68.             selArray[2] = selC;  
  69.         }  
  70.           
  71.         //清除下级子列表选项  
  72.         function clearSubSel(targetId) {  
  73.             var len = selArray.length;  
  74.             for(var i=0;i<len;i++) {  
  75.                 var j = 0;  
  76.                 if(selArray[i] == targetId) {  
  77.                     j = i;  
  78.                     break;  
  79.                 }  
  80.             }  
  81.             for(; j<len; j++) {  
  82.                 clearOptions(document.getElementById(selArray[j]));  
  83.             }  
  84.             //《Ajax经典案例开发大全》中该方法的代码是有误,不能实现下级列表全部清除功能,且代码冗余,如下示:  
  85.             //var canClear = false;  
  86.             //for(var i=0; i<selArray.length; i++) {  
  87.             //  if(selArray[i] == targetId) {  
  88.             //      canClear = true;  
  89.             //  }  
  90.             //  if(canClear) {  
  91.             //      clearOptions(document.getElementById(selArray[i]));  
  92.             //  }  
  93.             //}  
  94.         }  
  95.     </script>  
  96. </head>  
  97. <!-- 页面加载完毕做2件事:1.初始化列表数组,2.为第一个列表赋值 -->  
  98. <body onload="initSelArray('selA','selB','selC');buildSelect('INIT','selA')">  
  99.     <h1>多级联动菜单</h1>  
  100.     <table>  
  101.         <tr>  
  102.             <td>列表A</td>  
  103.             <td>  
  104.                 <select name="selA" id="selA" onchange="buildSelect(this.value,'selB')">  
  105.                     <option value="" selected>-------请选择-------</option>  
  106.                 </select>  
  107.             </td>  
  108.         </tr>  
  109.           
  110.         <tr>  
  111.             <td>列表B</td>  
  112.             <td>  
  113.                 <select name="selB" id="selB" onchange="buildSelect(this.value,'selC')">  
  114.                     <option value="" selected>-------请选择-------</option>  
  115.                 </select>  
  116.             </td>  
  117.         </tr>  
  118.           
  119.         <tr>  
  120.             <td>列表C</td>  
  121.             <td>  
  122.                 <select name="selC" id="selC">  
  123.                     <option value="" selected>-------请选择-------</option>  
  124.                 </select>  
  125.             </td>  
  126.         </tr>  
  127.     </table>  
  128. </body>  
  129. </html>  


 

        4.select_menu.jsp后台服务

[html]  view plain  copy
 print ?
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
  2.     pageEncoding="UTF-8"%>  
  3. <%@ page import="java.sql.*,com.lanp.ajax.db.DBUtils" %>      
  4. <%!  
  5.     //访问数据库取得下级选项信息  
  6.     String getOptions(String selectedId) {  
  7.         int counter = 0;  
  8.         StringBuffer opts = new StringBuffer("{");  
  9.         String sql = "select * from select_menu where pid=? order by seq asc";  
  10.         Connection conn = null;  
  11.         PreparedStatement pstmt = null;  
  12.         ResultSet rs = null;  
  13.         try {  
  14.             conn = DBUtils.getConnection();  
  15.             pstmt = conn.prepareStatement(sql);  
  16.             pstmt.setString(1,selectedId);  
  17.             rs = pstmt.executeQuery();  
  18.               
  19.             while(rs.next()) {  
  20.                 //如果不是第一项,追加一个","用于分隔选项  
  21.                 if(counter > 0) {  
  22.                     opts.append(",");  
  23.                 }  
  24.                 opts.append("'");  
  25.                 opts.append(rs.getString("id"));  
  26.                 opts.append("':'");  
  27.                 opts.append(rs.getString("text"));  
  28.                 opts.append("'");  
  29.                 counter++;  
  30.             }  
  31.         } catch(SQLException e) {  
  32.             System.out.println(e.toString());  
  33.         } finally {  
  34.             DBUtils.closeResources(conn,pstmt,rs);  
  35.         }  
  36.         opts.append("}");  
  37.         System.out.println(opts.toString());  
  38.         return opts.toString();  
  39.     }  
  40. %>  
  41.   
  42. <%  
  43.     out.clear();  
  44.     String selectedId = request.getParameter("selectedId");  
  45.     String optionsInfo = getOptions(selectedId);  
  46.     out.print(optionsInfo);  
  47. %>  


OK,TKS!

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值