使用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 offset函数应用实例
Nov 14 Javascript
DWZ table的原生分页浅谈
Mar 01 Javascript
浅谈利用JavaScript进行的DDoS攻击原理与防御
Jun 04 Javascript
js实现类似菜单风格的TAB选项卡效果代码
Aug 28 Javascript
AngularJS教程之简单应用程序示例
Aug 16 Javascript
php 修改密码实现代码
May 24 Javascript
Webpack执行命令参数详解
Jun 17 Javascript
JavaScript之面向对象_动力节点Java学院整理
Jun 29 Javascript
微信小程序实现文字跑马灯效果
May 26 Javascript
谈谈JavaScript中super(props)的重要性
Feb 12 Javascript
在js文件中引入(调用)另一个js文件的三种方法
Sep 11 Javascript
基于vue实现微博三方登录流程解析
Nov 04 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
PHP中把错误日志保存在系统日志中(Windows系统)
2015/06/23 PHP
laravel框架 laravel-admin上传图片到oss的方法
2019/10/13 PHP
PHP vsprintf()函数格式化字符串操作原理解析
2020/07/14 PHP
服务端 VBScript 与 JScript 几个相同特性的写法 By shawl.qiu
2007/03/06 Javascript
javascript中创建对象的三种常用方法
2010/12/30 Javascript
javascript继承之为什么要继承
2012/11/10 Javascript
浏览器的JavaScript引擎的识别方法
2013/10/20 Javascript
浅析JavaScript中的typeof运算符
2013/11/30 Javascript
JS获取各种浏览器窗口大小的方法
2014/01/14 Javascript
使用iframe window的scroll方法控制iframe页面滚动
2014/03/05 Javascript
js动态切换图片的方法
2015/01/20 Javascript
bootstrap datepicker插件默认英文修改为中文
2017/07/28 Javascript
纯js实现画一棵树的示例
2017/09/05 Javascript
Vue插值、表达式、分隔符、指令知识小结
2018/10/12 Javascript
在vue中获取微信支付code及code被占用问题的解决方法
2019/04/16 Javascript
详解在React-Native中持久化redux数据
2019/05/22 Javascript
VsCode与Node.js知识点详解
2019/09/05 Javascript
uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能
2019/11/12 Javascript
python实现用户管理系统
2018/01/10 Python
Django框架实现逆向解析url的方法
2018/07/04 Python
Python实现手写一个类似django的web框架示例
2018/07/20 Python
Python for循环通过序列索引迭代过程解析
2020/02/07 Python
Python版中国省市经纬度
2020/02/11 Python
基于python requests selenium爬取excel vba过程解析
2020/08/12 Python
Bowflex美国官方网站:高级家庭健身器材
2017/12/22 全球购物
如何写毕业求职自荐信
2013/11/06 职场文书
高中的自我鉴定
2013/12/16 职场文书
工作失误检讨书范文大全
2014/01/13 职场文书
个人批评与自我批评范文
2014/10/17 职场文书
预备党员群众意见
2015/06/01 职场文书
工作总结之小学教师体育工作范文(3篇)
2019/10/07 职场文书
导游词之青岛太清宫
2019/12/13 职场文书
elasticSearch-api的具体操作步骤讲解
2021/06/28 Java/Android
详解MySQL的主键查询为什么这么快
2022/04/03 MySQL
AJAX引擎原理以及XmlHttpRequest对象的axios、fetch区别详解
2022/04/09 Javascript
python APScheduler执行定时任务介绍
2022/04/19 Python