本期来讲解在 AJAX 中使用 json 格式数据. 不过我们先不说 json 的事, 先来做个案例, 然后由这个案例我们再来讨论为啥要用 json 数据, 以及怎么用.
一, 案例
非常经典, 也是非常简单的 AJAX 案例, 省市联动. 就是在网上常见的, 选择一个省份, 然后城市所在的 <select> 标签中再动态加载进来所选省份包含的城市选项.
html 是极其简单的. 为了让案例更简单, 省份的 < select > 标签中的选项都写死了, 其中 value 代表省份的主键 id. 城市所对应的 < select > 标签也是如此, 不在赘述.
<body>
省份:<select id="province">
- <option value="1">河北</option>
- <option value="2">河南</option>
- <option value="3">山东</option>
- <option value="4">山西</option>
- </select>
城市:<select id="city"></select>
</body>
后台代码也是非常简单的, 仍然使用一般处理程序, 如下.
其中 City 是城市实体类, 3 个字段.
需要简单说明的是这个一般处理程序, 它的思路是:
1. 通过 QueryString 获取到 get 请求传递过来的 proId(省份 id).
2. 根据 proId 从数据库中获取到包含的城市(IList<City>).
3. 遍历这个 IList<City > 城市集合, 然后拼写成类似于 "<option value='0100001'>成都 </option><option value='0100002'> 绵阳</option>......." 这样的字符串. 因为这样的字符串可以直接放到 < select > 标签对的内部, 形成该下拉选项框的选项.
- public class City
- {
- public int Id { get; set; }// 城市主键
- public string Name { get; set; }// 城市名字
- public int proId { get; set; }// 省份的 id
- }
- public class citysHandler : IHttpHandler
- {
- public void ProcessRequest(HttpContext context)
- {
- context.Response.ContentType = "text/plain";
- if (context.Request.HttpMethod.ToUpper() == "GET")
- {
- string proId = context.Request.QueryString["proId"];
- Citys citys = new Citys();
- IList<City> cList = citys.GetCitysByProId(proId);
- StringBuilder opts = new StringBuilder();
- foreach (City c in cList)
- {
- opts.Append("<option value='" + c.Id + "'>");
- opts.Append(c.Name);
- opts.Append("</option>");
- }
- context.Response.Write(opts.ToString());
- }
- }
- public bool IsReusable
- {
- get
- {
- return false;
- }
- }
- }
接下来是客户端代码. 当用户选择任意一个省份后, 触发该省份下拉框的 onchange 事件, 在该事件中使用 AJAX 方式, 发出 get 请求, 访问服务端 citysHandler.ashx. 代码如下:
代码没有太多需要解释的, 由于服务端直接返回的就是拼接好 html 标签的字符串, 所以直接作为 innerHTML 放到 < select id="city"><select > 里去就可以了, 倒是非常简单.
- <script>
- window.onload = function () {
- var selProv = document.getElementById("province");
- selProv.onchange = function () {
- if (window.XMLHttpRequest) {
- xhr = new XMLHttpRequest();
- }
- else {
- xhr = new ActiveXObject("Microsoft.XMLHTTP");
- }
- var proId = this.value;
- var url = "citysHandler.ashx" + "?proId=" + proId;
- xhr.open("get", url, true);
- xhr.setRequestHeader("If-Modified-Since", "0");
- xhr.onreadystatechange = function () {
- if (xhr.readyState == 4 && xhr.status == 200) {
- var opts = xhr.responseText;
- var selCity = document.getElementById("city");
- selCity.innerHTML = opts;
- }
- }
- xhr.send(null);
- }
- }
- </script>
二, 弊端
功能虽然实现了, 但是弊端还是挺大的.
1. 服务端返回的字符串不光包含需要展示给用户看的数据, 比如城市名字, 城市的 id, 更重要的是这些数据被 < option > 标签包住了. 换句话说服务端返回的数据不干净, 或者说不纯粹, 加载了太多 html 标签. 这么做的弊端在于把这个后端的数据接口限制死了, 由于 < option > 只能放在 < select > 标签中作为选项用, 那么如果以后客户希望在一个 < table > 中展示所有数据, 那么这个后台的服务就不可重用了.
2. 夹杂了很多 html 标签后, 要传输的数据量必定加大, 那么势必降低程序的性能, 至少客户端的响应速度会变慢, 这对于性能控制狂来说是不可接受的.
三, 改进 --json
json 只是一种数据格式, 它是从 JavaScript 的字面量表示法演变过来的, 也是 JavaScript 语言中的一种对象描述方式. 它的语法特别简单:{"key1" : "val1" , "key2" : "val2" , ....... }. 它与字面量表示法唯一的区别就是 json 格式要求所有的 key 和 value 都要用双引号引住, 单引号不可以, 不引更不可以.
好了, 先看服务端的代码改造吧. 只看一般处理程序的 PR 方法就 OK 了.
这里使用了 System.web.Script.Serialization.JavaScriptSerializer 对一个集合进行序列化, 序列化的结果当然就是一个 JSON 格式的字符串.
- public void ProcessRequest(HttpContext context)
- {
- context.Response.ContentType = "text/plain";
- if (context.Request.HttpMethod.ToUpper() == "GET")
- {
- string proId = context.Request.QueryString["proId"];
- Citys citys = new Citys();
- IList<City> cList = citys.GetCitysByProId(proId);
- System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer();
- string jsonCitys = jss.Serialize(cList);
- context.Response.Write(jsonCitys);
- }
- }
需要注意的是 JSON 对象与 JSON 格式的字符串是有本质不同的.
打个比方:
int i = 12345;
string str = "12345"; 看上去都是存的 12345, 但是有本质不同, 变量 i 存的是一个整数, 能做算术运算的整数; 而变量 str 里存的数据看上去也是 "12345", 但这是个字符串, 不能做算术运算.
如果你还不理解, 再来看个例子.
int[ ] arr = {22, 12, 34, 45}; 很显然这是个整形数组
"{22, 12, 34, 45}", 而这个是字符串, 只不过跟上边那个数组 "长得" 很像罢了.
所以这里经过. NET 提供的 JavaScriptSerializer 序列化过后的数据, 是个字符串, 长得样子大概就是 "[{"Id":1,"Name":" 成都 ","proId":5},{"Id":2,"Name":" 绵阳 ","proId":5},{"Id":3,"Name":" 广元 ","proId":5}]" 这个样子. 不过看好了, 两头有 "", 这个是个正经八百的字符串, 所以, 这样的数据传递到前端后, 我们需要使用 JavaScript 的方式, 把这个字符串再转换成 JSON 对象.
接下来改造前台 JavaScript 代码
只需要看回调函数就可以了, 其他地方不需要改.
- xhr.onreadystatechange = function () {
- if (xhr.readyState == 4 && xhr.status == 200) {
- var opts = xhr.responseText;
- var selCity = document.getElementById("city");
- //selCity.innerHTML = opts;
- var jsonCitys = JSON.parse(opts);
- for (var i = 0; i < jsonCitys.length; i++) {
- var opt = document.createElement("option");
- opt.setAttribute("value", jsonCitys[i].Id);
- opt.innerHTML = jsonCitys[i].Name;
- selCity.appendChild(opt);
- }
- }
- }
- xhr.send(null);
关键点是这条语句: var jsonCitys = JSON.parse(opts); JSON.parse()是 JavaScript 提供的 1 个 API, 它的作用是把一个 JSON 格式的字符串, 转化成一个 JSON 对象. 当然, 如果传递过来的字符串是一个由多个 JSON 格式对象组合成的数组样式的字符串, 就比如我们这里就是如此:"[{"Id":1,"Name":" 成都 ","proId":5},{"Id":2,"Name":" 绵阳 ","proId":5},{"Id":3,"Name":" 广元 ","proId":5}]" . 我们从后台得到的数据, 引号内部首先是一对 [ ] , 这个方括号显然就是 js 中数组的符号了.
那么这种情况下, JSON.parse()会把这个字符串解析成由多个 JSON 对象组成的一个 JavaScript 数组. 然后我们就能用 for 循环遍历它了.
接下来的 DOM 操作, 就不必细说了.
再回头看这个例子, 经过改造后, 后台传递来的数据是 "纯粹的", 不带有任何表示层的东西, 这样带来的好处: 1. 要传输的数据量小, 轻量化了. 2. 更利于表示层按各种要求展示, 表示层想怎么玩就怎么玩. 爽!
AJAX(四)实例 -- json 格式数据
来源: http://www.bubuko.com/infodetail-2653718.html