使用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 相关文章推荐
JQuery自定义事件的应用 JQuery最佳实践
Aug 01 Javascript
js封装的textarea操作方法集合(兼容很好)
Nov 16 Javascript
javascript中使用replaceAll()函数实现字符替换的方法
Dec 25 Javascript
DB.ASP 用Javascript写ASP很灵活很好用很easy
Jul 31 Javascript
用JS实现一个TreeMenu效果分享
Aug 28 Javascript
Javascript MVC框架Backbone.js详解
Sep 18 Javascript
浅谈JavaScript正则表达式分组匹配
Apr 10 Javascript
js实现简单的验证码
Dec 25 Javascript
Angularjs单选框相关的示例代码
Aug 17 Javascript
浅谈vue-cli加载不到dev-server.js的解决办法
Nov 24 Javascript
jQuery实现获取动态添加的标签对象示例
Jun 28 jQuery
JavaScript函数柯里化实现原理及过程
Dec 02 Javascript
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
删除无限级目录与文件代码共享
2006/07/12 PHP
window+nginx+php环境配置 附配置搭配说明
2010/12/29 PHP
php的array_multisort()使用方法介绍
2012/05/16 PHP
PHP基础陷阱题(变量赋值)
2012/09/12 PHP
ucenter通信原理分析
2015/01/09 PHP
php面向对象与面向过程两种方法给图片添加文字水印
2015/08/26 PHP
Symfony学习十分钟入门经典教程
2016/02/03 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
php无限级评论嵌套实现代码
2018/04/18 PHP
javascript实现仿银行密码输入框效果的代码
2007/12/13 Javascript
jQuery获得包含margin的outerWidth和outerHeight的方法
2015/03/25 Javascript
JavaScript中利用Array和Object实现Map的方法
2015/07/27 Javascript
通过jquery-ui中的sortable来实现拖拽排序的简单实例
2016/05/24 Javascript
基于JavaScript实现微信抢红包功能
2017/07/20 Javascript
通过button将form表单的数据提交到action层的实例
2017/09/08 Javascript
js最简单的双向绑定实例讲解
2018/01/02 Javascript
详解vuex之store拆分即多模块状态管理(modules)篇
2018/11/13 Javascript
vue中node_modules中第三方模块的修改使用详解
2019/05/31 Javascript
Python操作MySQL数据库9个实用实例
2015/12/11 Python
人生苦短我用python python如何快速入门?
2018/03/12 Python
Python获取系统所有进程PID及进程名称的方法示例
2018/05/24 Python
Python2包含中文报错的解决方法
2018/07/09 Python
PyCharm汉化安装及永久激活详细教程(靠谱)
2020/01/16 Python
python通过文本在一个图中画多条线的实例
2020/02/21 Python
jupyter notebook清除输出方式
2020/04/10 Python
使用Pycharm(Python工具)新建项目及创建Python文件的教程
2020/04/26 Python
Python+OpenCV图像处理——打印图片属性、设置存储路径、调用摄像头
2020/10/22 Python
python对输出的奇数偶数排序实例代码
2020/12/04 Python
网络公司美工设计工作个人的自我评价
2013/11/03 职场文书
婚礼答谢宴主持词
2014/03/14 职场文书
在职员工证明书
2014/09/19 职场文书
计生办班子群众路线教育实践活动个人对照检查材料思想汇报
2014/10/04 职场文书
专家推荐信怎么写
2015/03/25 职场文书
公司晚宴祝酒词
2015/08/11 职场文书
八年级作文之友情
2019/11/25 职场文书
Oracle 触发器trigger使用案例
2022/02/24 Oracle