使用jQuery+HttpHandler+xml模拟一个三级联动的例子


Posted in Javascript onAugust 09, 2011

如下是实现过程:
第一步:准备xml文件,并放置在网站根目录下,名为Area.xml

<?xml version="1.0" encoding="utf-8" ?> 
<area> 
<province id="1" name="北京"> 
<city id="1" name="北京"> 
<county id="1" name="东城区" /> 
<county id="2" name="西城区" /> 
</city> 
</province> 
<province id="2" name="河北省"> 
<city id="1" name="石家庄市"> 
<county id="1" name="正定县" /> 
<county id="2" name="灵寿县" /> 
</city> 
<city id="2" name="邯郸市"> 
<county id="1" name="邯郸县" /> 
<county id="2" name="永年县" /> 
</city> 
</province> 
<province id="3" name="海南省"> 
<city id="1" name="海口市"> 
<county id="1" name="龙华区" /> 
<county id="2" name="秀英区" /> 
<county id="3" name="美兰区" /> 
</city> 
<city id="2" name="三亚市"> 
<county id="1" name="天涯镇" /> 
<county id="2" name="凤凰镇" /> 
</city> 
</province> 
</area>

第二步:创建与xml文件中定义的元素对应的实体类。
<province/>对应province类
public class Province 
{ 
private string id; 
/// <summary> 
/// 编号 
/// </summary> 
public string Id 
{ 
get { return id; } 
set { id = value; } 
} 
private string name; 
/// <summary> 
/// 名称 
/// </summary> 
public string Name 
{ 
get { return name; } 
set { name = value; } 
} 
}

<city/>对应City类:
public class City 
{ 
private string id; 
/// <summary> 
/// 编号 
/// </summary> 
public string Id 
{ 
get { return id; } 
set { id = value; } 
} 
private string name; 
/// <summary> 
/// 名称 
/// </summary> 
public string Name 
{ 
get { return name; } 
set { name = value; } 
} 
}

<county/>对应county类:
public class County 
{ 
private string id; 
/// <summary> 
/// 编号 
/// </summary> 
public string Id 
{ 
get { return id; } 
set { id = value; } 
} 
private string name; 
/// <summary> 
/// 名称 
/// </summary> 
public string Name 
{ 
get { return name; } 
set { name = value; } 
} 
}

第三步:编写服务器端处理程序类:Handler.cs
/// <summary> 
2 /// 处理程序 
3 /// </summary> 
4 public class Handler : IHttpHandler 
5 { 
6 
7 private static XDocument doc; 
8 private string filePath = HttpContext.Current.Server.MapPath("~/Area.xml"); 
9 //javascript序列化类 
private static JavaScriptSerializer jss = new JavaScriptSerializer(); 
public void ProcessRequest(HttpContext context) 
{ 
context.Response.ContentType = "text/plain"; 
string result = "failure";//默认返回结果为失败 
HttpRequest req = context.Request; 
string province = req["province"];//获取用户选择的省的编号 
string city = req["city"];//获取用户选择的市的编号 
string county = req["county"];//获取用户选择的县的编号 
string type = req["type"];//获取用户需要获取的省市县列表的类型 
InitDoc(); 
if (type.HasValue()) 
{ 
switch (type.ToLower()) 
{ 
case "province"://如果用户需要获取省级列表 
result = jss.Serialize(GetProvinceList()); 
break; 
case "city"://如果用户需要获取的是市级列表 
result = jss.Serialize(GetCityListByProvince(province)); 
break; 
case "county"://如果用户需要获取的是县级列表 
result = jss.Serialize(GetCountyListByCity(province, city)); 
break; 
default: 
break; 
} 
} 
//将结果以文本的格式返回给客户端 
context.Response.Write(result); 
} 
/// <summary> 
/// 初始化文档对象 
/// </summary> 
private void InitDoc() 
{ 
if (doc == null) 
{ 
doc = XDocument.Load(filePath); 
} 
} 
/// <summary> 
/// 初始化省级列表 
/// </summary> 
private List<Province> GetProvinceList() 
{ 
List<Province> list = new List<Province>(); 
if (doc != null) 
{ 
XElement root = doc.Root; 
foreach (var prov in root.XPathSelectElements("province")) 
{ 
list.Add(new Province() 
{ 
Id = prov.Attribute("id").Value, 
Name = prov.Attribute("name").Value 
}); 
} 
} 
return list; 
} 
/// <summary> 
/// 根据省级编号获取市级编号 
/// </summary> 
/// <param name="provId">省级编号</param> 
private List<City> GetCityListByProvince(string provId) 
{ 
List<City> list = new List<City>(); 
if (doc != null) 
{ 
XElement root = doc.Root; 
//xpath表达式:/area/province[@id='1']/city 
string queryPath = "/area/province[@id='" + provId + "']/city"; 
foreach (var city in root.XPathSelectElements(queryPath)) 
{ 
list.Add(new City() 
{ 
Id = city.Attribute("id").Value, 
Name = city.Attribute("name").Value 
}); 
} 
} 
return list; 
} 
/// <summary> 
/// 根据省级编号和市级编号获取县级编号 
/// </summary> 
/// <param name="provId">省级编号</param> 
/// <param name="cityId">市级编号</param> 
private List<County> GetCountyListByCity(string provId, string cityId) 
{ 
List<County> list = new List<County>(); 
if (doc != null) 
{ 
XElement root = doc.Root; 
string queryPath = "/area/province[@id='" + provId + "']/city[@id='" + cityId + "']/county"; 
foreach (var county in root.XPathSelectElements(queryPath)) 
{ 
list.Add(new County() 
{ 
Id = county.Attribute("id").Value, 
Name = county.Attribute("name").Value 
}); 
} 
} 
return list; 
} 
public bool IsReusable 
{ 
get 
{ 
return false; 
} 
} 
}

在这里,查询xml我采用的是System.Xml.XPath命名空间下的XPathSelectElements(string xpath)方法和XPathSelectElement(string xpath)方法,在根据省级编号获取市级编号的方法里面,我使用了xpath表达式(假设传入的省级编号为1):/area/province[@id='1']/city,这个表达式以“/”开头,表示使用绝对路径,因为area为根节点所以从area开始,接着它下面有province元素,当我想获取area下所有province元素中id属性值为1的province元素时,我可以使用/area/province[@id='1'],即在province后面加上[@id='1']这个条件,这时我就获取到了area下id属性为1的province元素了。接着我要获取该province元素下所有的city,那么只需在后面加上/city即可,所以最终的xpath表达式为:/area/province[@id='1']/city。
还有,因为此查询的xml是在当前网站的根目录,如果是在其它地方,那么在查询的时候要加上namespace
将从xml文件中读取到的值组装成对应的实体对象只后,我使用了System.Web.Script.Serialization命名空间下的JavaScriptSerializer类中的Serialize方法将得到的实体对象序列化成json数据返回给客户端。
第四步:编写html和js。
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>省市县三级联动下拉列表</title> 
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script> 
<script type="text/javascript"> 
$(function () { 
$.post("/Handler.ashx", { "type": "province" }, function (data, status) { 
if (status == "success") { 
if (data != "failure") { 
data = $.parseJSON(data); //解析服务器返回的json数据 
for (var i = 0; i < data.length; i++) { 
var value = data[i].Id + ":" + data[i].Name; //设置option选项的值,格式为:"编号:名称" 
$("#province").append("<option value='" + value + "'>" + data[i].Name + "</option>"); 
} 
} 
} 
}, "text"); 
$("#province").change(function () { 
var selectValue = $(this).val(); //获取选择的省级option的值 
var provId = selectValue.split(':')[0]; //取出编号 
var provTxt = selectValue.split(':')[1]; //取出名称 
$("#txtProvince").html(provTxt); //显示选择的省的名称 
$("#city").html("<option>==请选择市==</option>"); //当省级改变时将市级清空 
$("#county").html("<option>==请选择县==</option>"); //当省级改变时将县级清空 
$.post("/Handler.ashx", { "province": provId, "type": "city" }, function (data, status) { 
if (status == "success") { 
if (data != "failure") { 
data = $.parseJSON(data); 
for (var i = 0; i < data.length; i++) { 
var value = data[i].Id + ":" + data[i].Name; 
$("#city").append("<option value='" + value + "'>" + data[i].Name + "</option>"); 
} 
} 
} 
}, "text"); 
}); 
$("#city").change(function () { 
var provId = $("#province").val().split(':')[0]; 
var selectValue = $(this).val(); //同上 
var cityId = selectValue.split(':')[0]; //同上 
var cityTxt = selectValue.split(':')[1]; //同上 
$("#txtCity").html(cityTxt); //显示选择的市的名称 
$("#county").html("<option>==请选择县==</option>"); //同上 
$.post("/Handler.ashx", { "province": provId, "city": cityId, "type": "county" }, function (data, status) { 
if (status == "success") { 
if (data != "failure") { 
data = $.parseJSON(data); 
for (var i = 0; i < data.length; i++) { 
var value = data[i].Id + ":" + data[i].Name; 
$("#county").append("<option value='" + value + "'>" + data[i].Name + "</option>"); 
} 
} 
} 
}, "text"); 
}); 
$("#county").change(function () { 
$("#txtCounty").html($(this).val().split(':')[1]); //显示选择的县的名称 
}); 
}); 
</script> 
</head> 
<body> 
<!--省--> 
<select id="province" name="province"> 
</select> 
<!--市--> 
<select id="city" name="city"> 
</select> 
<!--县--> 
<select id="county" name="county"> 
</select> 
<br /> 
<span id="txtProvince" style="color: #ff0000;"></span>- <span id="txtCity" style="color: #ff0000;"></span>- <span id="txtCounty" style="color: #ff0000;"></span> 
</body> 
</html>

关于使用jQuery与服务器通信,我使用的是$.post方法,该方法的具体使用可以参考jQuery官方文档,这里我想说的是,遍历后通过对象.属性访问时,这个属性的名字是区分大小写的,这个名字是服务器端定义的名字,因为服务器序列化的是服务器端的实体对象。
在这个例子中,关键点就是如何使用XPath表达式,如何调用System.Xml.XPath命名空间下的XPathSelectElements(string xpath)方法。
最终结果如下图:
使用jQuery+HttpHandler+xml模拟一个三级联动的例子
代码13,31,50行可以优化。
不建议多次修改DOM结构,可以拼接字符串后一次append
数据源是xml,我会用xslt来解析xml直接输出<option>,这样就不用再前台拼接字符串了。要求所有节点ID不能有相同。
<select id="province" name="province" next="#city"> 
</select> 
<select id="city" name="city" next="#county"> 
<option>==请选择市==</option> 
</select> 
</form> 
<select id="county" name="county"> 
<option>==请选择县==</option> 
</select> <script type="text/javascript"> 
$("#province,#city").change(function () { 
var nextSelect = $(this.getAttribute("next")); 
//if (nextSelect.size() > 0) { 
nextSelect.find("option:gt(0)").remove(); 
var _id = $(this).find("option:selected").val(); 
var query = { parentId: _id }; 
$.get("/Handler.ashx", query, function (data, status) { 
//... 
nextSelect.append("<option>...</option>...."); 
}); 
//} 
}); 
</script>
Javascript 相关文章推荐
关于javascript中的typeof和instanceof介绍
Dec 04 Javascript
jquery如何把参数列严格转换成数组实现思路
Apr 01 Javascript
js单例模式的两种方案
Oct 22 Javascript
jQuery对象的length属性用法实例
Dec 27 Javascript
JavaScript原生对象之String对象的属性和方法详解
Mar 13 Javascript
Javascript中的arguments与重载介绍
Mar 15 Javascript
JS根据生日月份和日期计算星座的简单实现方法
Nov 24 Javascript
JS打开摄像头并截图上传示例
Feb 18 Javascript
vue.js实例todoList项目
Jul 07 Javascript
vue如何安装使用Quill富文本编辑器
Sep 21 Javascript
微信小程序控制台提示warning:Now you can provide attr &quot;wx:key&quot; for a &quot;wx:for&quot; to improve performance解决方法
Feb 21 Javascript
vue编写简单的购物车功能
Jan 08 Vue.js
js 分页全选或反选标识实现代码
Aug 09 #Javascript
js字符串的各种格式的转换 ToString,Format
Aug 08 #Javascript
Jquery ajax传递复杂参数给WebService的实现代码
Aug 08 #Javascript
jquery学习笔记 用jquery实现无刷新登录
Aug 08 #Javascript
基于jQuery实现的水平和垂直居中的div窗口
Aug 08 #Javascript
关于hashchangebroker和statehashable的补充文档
Aug 08 #Javascript
基于jQuery的前端数据通用验证库
Aug 08 #Javascript
You might like
PHP数据库万能引擎类adodb配置使用以及实例集锦
2014/06/12 PHP
ThinkPHP无限级分类原理实现留言与回复功能实例
2014/10/31 PHP
php抛出异常与捕捉特定类型的异常详解
2016/10/26 PHP
PHP两种实现无级递归分类的方法
2017/03/02 PHP
JS中toFixed()方法引起的问题如何解决
2012/11/20 Javascript
多个datatable共存造成多个表格的checkbox都被选中
2013/07/11 Javascript
Jquery图片延迟加载插件jquery.lazyload.js的使用方法
2014/05/21 Javascript
js,jquery滚动/跳转页面到指定位置的实现思路
2014/06/03 Javascript
使用GruntJS构建Web程序之安装篇
2014/06/04 Javascript
jQuery结合ajax实现动态加载文本内容
2015/05/19 Javascript
JavaScript中使用数组方法汇总
2016/02/16 Javascript
vue实现添加标签demo示例代码
2017/01/21 Javascript
使用ionic播放轮询广告的实现方法(必看)
2017/04/24 Javascript
JS获取url参数,JS发送json格式的POST请求方法
2018/03/29 Javascript
Angular入口组件(entry component)与声明式组件的区别详解
2018/04/09 Javascript
浅析vue给不同环境配置不同打包命令
2018/08/17 Javascript
使用pm2部署node生产环境的方法步骤
2019/03/09 Javascript
Vue如何基于es6导入外部js文件
2020/05/15 Javascript
[01:20:05]DOTA2-DPC中国联赛 正赛 Ehome vs VG BO3 第二场 2月5日
2021/03/11 DOTA
python实现通过pil模块对图片格式进行转换的方法
2015/03/24 Python
使用python画个小猪佩奇的示例代码
2018/06/06 Python
Python基于pyCUDA实现GPU加速并行计算功能入门教程
2018/06/19 Python
python实现倒计时小工具
2019/07/29 Python
对YOLOv3模型调用时候的python接口详解
2019/08/26 Python
基于Keras的格式化输出Loss实现方式
2020/06/17 Python
如何通过命令行进入python
2020/07/06 Python
python中如何设置代码自动提示
2020/07/15 Python
一文解决django 2.2与mysql兼容性问题
2020/07/15 Python
解决Firefox下不支持outerHTML问题代码分享
2014/06/04 HTML / CSS
瑞典快乐袜子:Happy Socks
2018/02/16 全球购物
乐高西班牙官方商店:LEGO Shop ES
2019/12/01 全球购物
《太阳》教学反思
2014/02/21 职场文书
大学生推广普通话演讲稿
2014/09/21 职场文书
群众路线自我剖析及整改措施
2014/11/04 职场文书
计划生育目标责任书
2015/05/09 职场文书
pytorch通过训练结果的复现设置随机种子
2021/06/01 Python