使用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代码优化之基本事件
Nov 01 Javascript
js给onclick赋值传参数的两种方法
Nov 25 Javascript
禁用JavaScript控制台调试的方法
Mar 07 Javascript
jQuery中选择器小问题(新人难免遇到)
Mar 31 Javascript
JavaScript程序设计之JS调试
Dec 09 Javascript
JS之相等操作符详解
Sep 13 Javascript
从源码看angular/material2 中 dialog模块的实现方法
Oct 18 Javascript
Vue表单demo v-model双向绑定问题
Jun 29 Javascript
webpack4 处理CSS的方法示例
Sep 03 Javascript
Vue弹出菜单功能的实现代码
Sep 12 Javascript
如何用JavaScript实现功能齐全的单链表详解
Feb 11 Javascript
Vue-Ant Design Vue-普通及自定义校验实例
Oct 24 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
PHPCrawl爬虫库实现抓取酷狗歌单的方法示例
2017/12/21 PHP
PHP定义字符串的四种方式详解
2018/02/06 PHP
ASP 过滤数组重复数据函数(加强版)
2010/05/31 Javascript
js浮点数保留两位小数点示例代码(四舍五入)
2013/12/26 Javascript
node.js中的path.dirname方法使用说明
2014/12/09 Javascript
jquery右下角自动弹出可关闭的广告层
2015/05/08 Javascript
Bootstrap树形控件使用方法详解
2016/01/27 Javascript
jQuery自定义数值抽奖活动代码
2016/06/11 Javascript
jQuery插入节点和移动节点用法示例(insertAfter、insertBefore方法)
2016/09/08 Javascript
微信小程序 Tab页切换更新数据
2017/01/05 Javascript
js实现日历与定时器
2017/02/22 Javascript
NodeJs中express框架的send()方法简介
2017/06/20 NodeJs
vue init webpack myproject构建项目 ip不能访问的解决方法
2018/03/20 Javascript
jquery引入外部CDN 加载失败则引入本地jq库
2018/05/23 jQuery
浅析Vue 和微信小程序的区别、比较
2018/08/03 Javascript
详解微信小程序-扫一扫 wx.scanCode() 扫码大变身
2019/04/30 Javascript
JS实现拖拽元素时与另一元素碰撞检测
2020/08/27 Javascript
js实现随机圆与矩形功能
2020/10/29 Javascript
JavaScript canvas实现文字时钟
2021/01/10 Javascript
Python3中的2to3转换工具使用示例
2015/06/12 Python
Python中有趣在__call__函数
2015/06/21 Python
Python基于Socket实现的简单聊天程序示例
2017/08/05 Python
Python正确重载运算符的方法示例详解
2017/08/27 Python
11月编程语言排行榜 Python逆袭C#上升到第4
2017/11/15 Python
Python中psutil的介绍与用法
2019/05/02 Python
pycharm的python_stubs问题
2020/04/08 Python
浅谈OpenCV中的新函数connectedComponentsWithStats用法
2020/07/05 Python
详解css3 object-fit属性
2018/07/27 HTML / CSS
开学季活动策划方案
2014/02/28 职场文书
幼儿园六一儿童节活动方案
2014/08/26 职场文书
办公室领导干部作风整顿个人整改措施
2014/09/17 职场文书
好媳妇事迹材料
2014/12/24 职场文书
谢师宴邀请函
2015/02/02 职场文书
2016年社区创先争优活动总结
2016/04/05 职场文书
python生成随机数、随机字符、随机字符串
2021/04/06 Python
tensorflow中的梯度求解及梯度裁剪操作
2021/05/26 Python