Discuz教程网

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

[复制链接]
authicon dly 发表于 2011-9-12 15:18:36 | 显示全部楼层 |阅读模式
如下是实现过程:
第一步:准备xml文件,并放置在网站根目录下,名为Area.xml
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <area>
  3. <province id="1" name="北京">
  4. <city id="1" name="北京">
  5. <county id="1" name="东城区" />
  6. <county id="2" name="西城区" />
  7. </city>
  8. </province>
  9. <province id="2" name="河北省">
  10. <city id="1" name="石家庄市">
  11. <county id="1" name="正定县" />
  12. <county id="2" name="灵寿县" />
  13. </city>
  14. <city id="2" name="邯郸市">
  15. <county id="1" name="邯郸县" />
  16. <county id="2" name="永年县" />
  17. </city>
  18. </province>
  19. <province id="3" name="海南省">
  20. <city id="1" name="海口市">
  21. <county id="1" name="龙华区" />
  22. <county id="2" name="秀英区" />
  23. <county id="3" name="美兰区" />
  24. </city>
  25. <city id="2" name="三亚市">
  26. <county id="1" name="天涯镇" />
  27. <county id="2" name="凤凰镇" />
  28. </city>
  29. </province>
  30. </area>
复制代码

第二步:创建与xml文件中定义的元素对应的实体类。
<province/>对应province类
  1. public class Province
  2. {
  3. private string id;
  4. /// <summary>
  5. /// 编号
  6. /// </summary>
  7. public string Id
  8. {
  9. get { return id; }
  10. set { id = value; }
  11. }
  12. private string name;
  13. /// <summary>
  14. /// 名称
  15. /// </summary>
  16. public string Name
  17. {
  18. get { return name; }
  19. set { name = value; }
  20. }
  21. }
复制代码

<city/>对应City类:
  1. public class City
  2. {
  3. private string id;
  4. /// <summary>
  5. /// 编号
  6. /// </summary>
  7. public string Id
  8. {
  9. get { return id; }
  10. set { id = value; }
  11. }
  12. private string name;
  13. /// <summary>
  14. /// 名称
  15. /// </summary>
  16. public string Name
  17. {
  18. get { return name; }
  19. set { name = value; }
  20. }
  21. }
复制代码

<county/>对应county类:
  1. public class County
  2. {
  3. private string id;
  4. /// <summary>
  5. /// 编号
  6. /// </summary>
  7. public string Id
  8. {
  9. get { return id; }
  10. set { id = value; }
  11. }
  12. private string name;
  13. /// <summary>
  14. /// 名称
  15. /// </summary>
  16. public string Name
  17. {
  18. get { return name; }
  19. set { name = value; }
  20. }
  21. }
复制代码

第三步:编写服务器端处理程序类:Handler.cs
  1. /// <summary>
  2. 2 /// 处理程序
  3. 3 /// </summary>
  4. 4 public class Handler : IHttpHandler
  5. 5 {
  6. 6
  7. 7 private static XDocument doc;
  8. 8 private string filePath = HttpContext.Current.Server.MapPath("~/Area.xml");
  9. 9 //javascript序列化类
  10. private static JavaScriptSerializer jss = new JavaScriptSerializer();
  11. public void ProcessRequest(HttpContext context)
  12. {
  13. context.Response.ContentType = "text/plain";
  14. string result = "failure";//默认返回结果为失败
  15. HttpRequest req = context.Request;
  16. string province = req["province"];//获取用户选择的省的编号
  17. string city = req["city"];//获取用户选择的市的编号
  18. string county = req["county"];//获取用户选择的县的编号
  19. string type = req["type"];//获取用户需要获取的省市县列表的类型
  20. InitDoc();
  21. if (type.HasValue())
  22. {
  23. switch (type.ToLower())
  24. {
  25. case "province"://如果用户需要获取省级列表
  26. result = jss.Serialize(GetProvinceList());
  27. break;
  28. case "city"://如果用户需要获取的是市级列表
  29. result = jss.Serialize(GetCityListByProvince(province));
  30. break;
  31. case "county"://如果用户需要获取的是县级列表
  32. result = jss.Serialize(GetCountyListByCity(province, city));
  33. break;
  34. default:
  35. break;
  36. }
  37. }
  38. //将结果以文本的格式返回给客户端
  39. context.Response.Write(result);
  40. }
  41. /// <summary>
  42. /// 初始化文档对象
  43. /// </summary>
  44. private void InitDoc()
  45. {
  46. if (doc == null)
  47. {
  48. doc = XDocument.Load(filePath);
  49. }
  50. }
  51. /// <summary>
  52. /// 初始化省级列表
  53. /// </summary>
  54. private List<Province> GetProvinceList()
  55. {
  56. List<Province> list = new List<Province>();
  57. if (doc != null)
  58. {
  59. XElement root = doc.Root;
  60. foreach (var prov in root.XPathSelectElements("province"))
  61. {
  62. list.Add(new Province()
  63. {
  64. Id = prov.Attribute("id").Value,
  65. Name = prov.Attribute("name").Value
  66. });
  67. }
  68. }
  69. return list;
  70. }
  71. /// <summary>
  72. /// 根据省级编号获取市级编号
  73. /// </summary>
  74. /// <param name="provId">省级编号</param>
  75. private List<City> GetCityListByProvince(string provId)
  76. {
  77. List<City> list = new List<City>();
  78. if (doc != null)
  79. {
  80. XElement root = doc.Root;
  81. //xpath表达式:/area/province[@id='1']/city
  82. string queryPath = "/area/province[@id='" + provId + "']/city";
  83. foreach (var city in root.XPathSelectElements(queryPath))
  84. {
  85. list.Add(new City()
  86. {
  87. Id = city.Attribute("id").Value,
  88. Name = city.Attribute("name").Value
  89. });
  90. }
  91. }
  92. return list;
  93. }
  94. /// <summary>
  95. /// 根据省级编号和市级编号获取县级编号
  96. /// </summary>
  97. /// <param name="provId">省级编号</param>
  98. /// <param name="cityId">市级编号</param>
  99. private List<County> GetCountyListByCity(string provId, string cityId)
  100. {
  101. List<County> list = new List<County>();
  102. if (doc != null)
  103. {
  104. XElement root = doc.Root;
  105. string queryPath = "/area/province[@id='" + provId + "']/city[@id='" + cityId + "']/county";
  106. foreach (var county in root.XPathSelectElements(queryPath))
  107. {
  108. list.Add(new County()
  109. {
  110. Id = county.Attribute("id").Value,
  111. Name = county.Attribute("name").Value
  112. });
  113. }
  114. }
  115. return list;
  116. }
  117. public bool IsReusable
  118. {
  119. get
  120. {
  121. return false;
  122. }
  123. }
  124. }
复制代码

在这里,查询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。
  1. <html xmlns="http://www.w3.org/1999/xhtml">
  2. <head>
  3. <title>省市县三级联动下拉列表</title>
  4. <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
  5. <script type="text/javascript">
  6. $(function () {
  7. $.post("/Handler.ashx", { "type": "province" }, function (data, status) {
  8. if (status == "success") {
  9. if (data != "failure") {
  10. data = $.parseJSON(data); //解析服务器返回的json数据
  11. for (var i = 0; i < data.length; i++) {
  12. var value = data[i].Id + ":" + data[i].Name; //设置option选项的值,格式为:"编号:名称"
  13. $("#province").append("<option value='" + value + "'>" + data[i].Name + "</option>");
  14. }
  15. }
  16. }
  17. }, "text");
  18. $("#province").change(function () {
  19. var selectValue = $(this).val(); //获取选择的省级option的值
  20. var provId = selectValue.split(':')[0]; //取出编号
  21. var provTxt = selectValue.split(':')[1]; //取出名称
  22. $("#txtProvince").html(provTxt); //显示选择的省的名称
  23. $("#city").html("<option>==请选择市==</option>"); //当省级改变时将市级清空
  24. $("#county").html("<option>==请选择县==</option>"); //当省级改变时将县级清空
  25. $.post("/Handler.ashx", { "province": provId, "type": "city" }, function (data, status) {
  26. if (status == "success") {
  27. if (data != "failure") {
  28. data = $.parseJSON(data);
  29. for (var i = 0; i < data.length; i++) {
  30. var value = data[i].Id + ":" + data[i].Name;
  31. $("#city").append("<option value='" + value + "'>" + data[i].Name + "</option>");
  32. }
  33. }
  34. }
  35. }, "text");
  36. });
  37. $("#city").change(function () {
  38. var provId = $("#province").val().split(':')[0];
  39. var selectValue = $(this).val(); //同上
  40. var cityId = selectValue.split(':')[0]; //同上
  41. var cityTxt = selectValue.split(':')[1]; //同上
  42. $("#txtCity").html(cityTxt); //显示选择的市的名称
  43. $("#county").html("<option>==请选择县==</option>"); //同上
  44. $.post("/Handler.ashx", { "province": provId, "city": cityId, "type": "county" }, function (data, status) {
  45. if (status == "success") {
  46. if (data != "failure") {
  47. data = $.parseJSON(data);
  48. for (var i = 0; i < data.length; i++) {
  49. var value = data[i].Id + ":" + data[i].Name;
  50. $("#county").append("<option value='" + value + "'>" + data[i].Name + "</option>");
  51. }
  52. }
  53. }
  54. }, "text");
  55. });
  56. $("#county").change(function () {
  57. $("#txtCounty").html($(this).val().split(':')[1]); //显示选择的县的名称
  58. });
  59. });
  60. </script>
  61. </head>
  62. <body>
  63. <!--省-->
  64. <select id="province" name="province">
  65. </select>
  66. <!--市-->
  67. <select id="city" name="city">
  68. </select>
  69. <!--县-->
  70. <select id="county" name="county">
  71. </select>
  72. <br />
  73. <span id="txtProvince" style="color: #ff0000;"></span>- <span id="txtCity" style="color: #ff0000;"></span>- <span id="txtCounty" style="color: #ff0000;"></span>
  74. </body>
  75. </html>
复制代码

关于使用jQuery与服务器通信,我使用的是$.post方法,该方法的具体使用可以参考jQuery官方文档,这里我想说的是,遍历后通过对象.属性访问时,这个属性的名字是区分大小写的,这个名字是服务器端定义的名字,因为服务器序列化的是服务器端的实体对象。
在这个例子中,关键点就是如何使用XPath表达式,如何调用System.Xml.XPath命名空间下的XPathSelectElements(string xpath)方法。
最终结果如下图:

代码13,31,50行可以优化。
不建议多次修改DOM结构,可以拼接字符串后一次append
数据源是xml,我会用xslt来解析xml直接输出<option>,这样就不用再前台拼接字符串了。要求所有节点ID不能有相同。
  1. <select id="province" name="province" next="#city">
  2. </select>
  3. <select id="city" name="city" next="#county">
  4. <option>==请选择市==</option>
  5. </select>
  6. </form>
  7. <select id="county" name="county">
  8. <option>==请选择县==</option>
  9. </select>

  10. <script type="text/javascript">
  11. $("#province,#city").change(function () {
  12. var nextSelect = $(this.getAttribute("next"));

  13. //if (nextSelect.size() > 0) {
  14. nextSelect.find("option:gt(0)").remove();

  15. var _id = $(this).find("option:selected").val();
  16. var query = { parentId: _id };
  17. $.get("/Handler.ashx", query, function (data, status) {
  18. //...
  19. nextSelect.append("<option>...</option>....");
  20. });
  21. //}
  22. });
  23. </script>
复制代码



上一篇:js字符串的各种格式的转换 ToString,Format
下一篇:jquery学习笔记 用jquery实现无刷新登录
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1314学习网 ( 浙ICP备10214163号 )

GMT+8, 2025-5-2 20:07

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表