(转载)Ajax初步认识
最近在学习Ajax,这真是个好东西啊,能大大调高用户的体验,异步式的开发着实很爽,前段时间刚学asp.net webform时候,没有ajax有很多操作要不同的页面进行操作,要不停的跳转,如果页面再有一堆服务端控件,着实不爽,体验特别的不舒服.Ajax是什么东西,我就不说了,大家都知道,本人刚学这个,发现写js代码十分的不熟,以后要多练练,下面我就分享我学习过程中的一些实际运用Ajax的Demo,着实没什么技术,纯粹的分享,让没有学过Ajax的能够了解Ajax的一些基本用法,大家共同学习,共同进步,Demo很简单利用AJAX的CRUD和分页等..
加载数据跟分页
首先我们自己搭建个表,具体的字段可以自己来设置,然后增加点数据即可,自己写分页存储过程,这个分页存储我直接用的代码生成器生成,其实大家可以根据自己的需求来写分页,然后我是用的三层,如果自己写分页存储过程,可以自己写Dal层的代码,会比较麻烦,但是写一次以后都能用了..我偷懒了直接用动软那套了.然后分页还需要一个生成html字符串的代码,用于在前台生成页码超链接,我本来想把它改成JS方法的,但是没成功,js实在烂,这样可以再后台穿参数过去即可,不需要传html标签字符串,增加传输量,具体的如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
public static string ShowPageNavigate( int pageSize, int currentPage, int totalCount) { string redirectTo = "" ; pageSize = pageSize == 0 ? 3 : pageSize; var totalPages = Math.Max((totalCount + pageSize - 1) / pageSize, 1); //总页数 var output = new StringBuilder(); if (totalPages > 1) { if (currentPage != 1) { //处理首页连接 output.AppendFormat( "<a class='pageLink' href='{0}?pageIndex=1&pageSize={1}'>首页</a> " , redirectTo, pageSize); } if (currentPage > 1) { //处理上一页的连接 output.AppendFormat( "<a class='pageLink' href='{0}?pageIndex={1}&pageSize={2}'>上一页</a> " , redirectTo, currentPage - 1, pageSize); } else { // output.Append("<span class='pageLink'>上一页</span>"); } output.Append( " " ); int currint = 5; for ( int i = 0; i <= 10; i++) { //一共最多显示10个页码,前面5个,后面5个 if ((currentPage + i - currint) >= 1 && (currentPage + i - currint) <= totalPages) { if (currint == i) { //当前页处理 //output.Append(string.Format("[{0}]", currentPage)); output.AppendFormat( "<a class='cpb' href='{0}?pageIndex={1}&pageSize={2}'>{3}</a> " , redirectTo, currentPage, pageSize, currentPage); } else { //一般页处理 output.AppendFormat( "<a class='pageLink' href='{0}?pageIndex={1}&pageSize={2}'>{3}</a> " , redirectTo, currentPage + i - currint, pageSize, currentPage + i - currint); } } output.Append( " " ); } if (currentPage < totalPages) { //处理下一页的链接 output.AppendFormat( "<a class='pageLink' href='{0}?pageIndex={1}&pageSize={2}'>下一页</a> " , redirectTo, currentPage + 1, pageSize); } else { //output.Append("<span class='pageLink'>下一页</span>"); } output.Append( " " ); if (currentPage != totalPages) { output.AppendFormat( "<a class='pageLink' href='{0}?pageIndex={1}&pageSize={2}'>末页</a> " , redirectTo, totalPages, pageSize); } output.Append( " " ); } output.AppendFormat( "第{0}页 / 共{1}页" , currentPage, totalPages); //这个统计加不加都行 return output.ToString(); } |
有了这个类,我们下面还是着手第一件事:加载数据到页面,这是我用的纯html页面跟一般处理程序来处理,避免走webform那一陀的生命周期,首先需要一个展示UserList的页面和一个加载数据的一般处理程序LoadUserList.ashx,展示页面里面可以用一个表格来展示了,首先我们在页面前面引用jquery跟jquery-UI等需要用到的文件,再写个table,具体如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<body> <table id= "userListTab" > <tr> <th>编号 </th> <th>登录名 </th> <th>电话 </th> <th>邮箱 </th> <th>操作 </th> </tr> </table><br /><!--页面分页 --><BR> <div id= "pageNavigation" ></div> |
pageNavigation层用于放分页导航.具体的后台代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain" ; int pageSize = context.Request[ "pageSize" ] == null ? 5 : int .Parse(context.Request[ "pageSize" ]); int pageIndex = context.Request[ "pageIndex" ] == null ? 1 : int .Parse(context.Request[ "pageIndex" ]); int totalCount = 0; totalCount = new BLL.HKSJ_USERS().GetRecordCount( string .Empty); List<Model.HKSJ_USERS> users = new List<Model.HKSJ_USERS>(); DataSet ds = new BLL.HKSJ_USERS().GetListByPage( string .Empty, "Id" , (pageIndex - 1) * pageSize + 1, pageIndex * pageSize); users = new BLL.HKSJ_USERS().DataTableToList(ds.Tables[0]); var pageNavigation = Common.LaomaPager.ShowPageNavigate(pageSize, pageIndex, totalCount); var data = new { trData=users,pageNavigation }; string htmlString = new JavaScriptSerializer().Serialize(data); context.Response.Write(htmlString); } |
当页面加载的时候发送一个异步请求到后台,默认加载页面时没有context.request["pageSize"]跟["pageIndex"]这个参数的,我们默认显示5个跟第1页,后面是取得根据具体分页等到的实体,我把他们放在list<model>中,方便后面序列化成json对象,然后根据pageSize跟pageIndex得到回传回去具体的html代码(就是一些a标签),把pageNavigation and Users序列化Json对象,我直接用JavaScriptSerializer来序列化,当然你可以自己拼接字符串(比较灵活,就是比较麻烦,有很多转义)...后台大致写好了,下面开始写前台的js代码,我觉的我们一定要会调试js代码,不然写js代码特别麻烦,不像vs写C#代码出错各种提示,后面会说点我自己的调试的方法,写js代码要注意很多,我自己也写的不熟,以后要多练练..好下面我们来写前台的代码..思路具体如下:
- 首先页面加载发送个一个异步请求到后台,取得数据(json),在前台动态生成html标签(也可以在后台拼接好了html再传到前台,但是增加传输量,这就是我想把那个类改成js版的原因)
- 将生成的html代码append到你所想展示的地方,我是展示到table里面,把这个两个步骤封装成一个方法function
- 加载数据算是完成,下面开始加载分页导航,同样页面加载的时候发送一个请求到后台,这里我都请求同一个一般处理程序,因为返回的数据两者都包含了.
- 下面要给分页导航的a标签注册事件,并且不执行跳转,同样是也异步化的
具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
function InitUserListByPage(requestData) { //每次加载先删除再加载 $( '#userListTab tr:gt(0)' ).remove(); //异步请求 $.getJSON( "LoadUserList.ashx" , requestData, function (data) { for (i = 0; i < data.trData.length; i++) { var htmlString = "<tr><td id='ID'>" + data.trData[i].ID + "</td><td id='LoginName'>" + data.trData[i].LoginName + "</td><td id='Phone'>" + data.trData[i].phone + "</td><td id='Mail'>" + data.trData[i].Mail + "</td><td><a href='DeleteUser.ashx?id=" + data.trData[i].ID + "' class='DeleteLink' userId=" + data.trData[i].ID + ">删除</a></td><td><a href='UpdateUser.ashx?id=" + data.trData[i].ID + "' class='UpdateLink' userId=" + data.trData[i].ID + ">添加</a></td><tr>" ; $( '#userListTab' ).append(htmlString); } DeleUser(); Edituser(); }); } function InitPageNavigation(requestData) { $.getJSON( "LoadUserList.ashx" , requestData, function (data) { var htmlString = data.pageNavigation; $( "#pageNavigation" ).html(htmlString); $( ".pageLink" ).click( function () { var strHref = $( this ).attr( "href" ); strHref = strHref.substring(strHref.lastIndexOf( '?' ) + 1, strHref.length); InitPageNavigation(strHref); InitUserListByPage(strHref); return false ; }) }) } |
关于页面分页有些地方要说下:strHref是用来获取发送到后台的参数:pageSize=1&pageIndex=5 这个字符串的,为超连接注册事件,首先获得所有的超链接(这个当前页面没有获得,因为当前的页面的class不是pageLink),点击后我们要重新加载数据跟分页,这里自己调用自己,联合上面给出的加载数据的方法,是很容易理解的,也就是是重新获取数据跟分页.参数requsetData表示的是pageSize=1&pageIndex=5这个样子的,如果没有后台也做了处理默认给你第一页跟5条数据,这一般加载的时候才传个空数据.加载的代码如下,直接调用两个方法即可
1
2
3
4
5
6
|
$(function () { //init table $( '#EditUser' ).css( "display" , "none" ); InitUserListByPage(); //innit pagenavagation InitPageNavigation(); |
这样根据页码跟页数得到数据,并且页面不用跳转:具体效果如下:不足之处在于点击当前页还是会刷新,这个很好解决,给当前也注册事件就OK了~
删除数据
下面所要做的操作就是删除数据,这个就简单了,发个一个异步请求到后台,删除即可,我的做法就是在生成表格后加个删除超链接,为超连接都加上个class="deleteLink"跟"UserID" =前面或者的ID,这样就方便传递ID跟或者a标签,需要注意的就是给a标签注册事件事件时必须在加载表格后再注册,不然会失效的,同样的我们封装成一个方法function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
function DeleUser() { $( '.DeleteLink' ).click( function () { var userId = $( this ).attr( "userId" ); var td = $( this ); if (confirm( "are you sure" )) { $.get( "DeleteUser.ashx" , { id: userId }, function (data) { if (data = "true" ) { td.parent().parent().hide( "slow" ); } else { alert( "Error" ); } }); } return false ; }); } |
一般删除都需要有个确认,这里用confirm来确定,必须return false,后台代码很简单根据Id删除就行了,返回true or false
添加数据
如同删除一样在后面加上添加超链接,并给超连接注册事件,这里我是点击,然后弹出个层来给用户修改,上面展示数据,有个修改按钮,并且给按钮注册事件,也就是给后台修改同样是异步,弹出个遮罩层我直接用jquery-ui来了,自己写也能写,但又要写一陀.刚开始的时候,我们首先让修改层隐藏,点击超链接,层出现,并把数据显示出来,后台修改也要把原来的数据都查数来,因为有些数据是不会给用户看的,更新的时候统统要更新的,后台代码逻辑很简单.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<!--修改层--> <div id= "EditUser" > <table> <tr> <td>编号</td> <td> <input type= "hidden" name= "hidden" value= " " id= "hidden" /> <span id= "txtShowId" ></span></td> <td>登录名</td> <td> <input type= "text" name= "LoginNameShow" value= " " id= "LoginNameShow" /></td> <td>电话</td> <td> <input type= "text" name= "PhoneShow" value= " " id= "PhoneShow" /></td> <td>邮箱</td> <td> <input type= "text" name= "MailShow" value= " " id= "MailShow" /> </td> <td colspan= "2" > <input type= "button" name= "Update" value= "Update" id= "Update" /></td> </tr> </table> </div> |
这里面需要个隐藏域来向后台传递ID,超链接的注册事件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
//注册添加用户事件 function Edituser() { $( '.UpdateLink' ).click( function () { var id = $( this ).attr( 'userId' ); $.getJSON( "GetUserInfoById.ashx" , { id: id }, function (data) { $( "#hidden" ).val(data.ID); $( "#txtShowId" ).text(data.ID); $( "#LoginNameShow" ).val(data.LoginName); $( "#MailShow" ).val(data.Mail); $( '#PhoneShow' ).val(data.phone); }) //$("#hidden").val(id); //$('#txtShowId').text(id); $( "#EditUser" ).dialog({ //设置div为dialog autoOpen: false , title: "注册用户" , height: 400, width: 1000, modal: true }); $( "#EditUser" ).dialog( "open" ); return false ; }) } |
这里显示数据我是直接发个请求到后台根据ID或者数据,然后显示到层上,下面就是给Update注册事件了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
function UpdateUser() { $( '#Update' ).click( function () { var JsonData = { Id: $( "#hidden" ).val(), Phone: $( '#PhoneShow' ).val(), LoginName: $( "#LoginNameShow" ).val(), Mail: $( "#MailShow" ).val() } $.get( "UpdateUser.ashx" , JsonData, function (data) { if (data = "true" ) { $( "#EditUser" ).dialog( "close" ); InitUserListByPage(); } }) }) } |
具体效果如下:
其实添加一般都是用户注册的,我们可以不用一个隐藏的层,我们可以用一个iframe指向注册页面,点击超链接,然后iframe显示,用户注册.如果要用iframe指向一个写好的页面来实现无刷新效果的话,ifame不能操作父页面的元素,这就带来了不方便.我们一般是这样父类提供一个属性或者方法,你可以调用方法来更改父类的私有字段,这里我们在原页面加入一个方法:
1
2
3
4
5
|
function afterRegistSuccess() { $( "#showRegistUser" ).dialog( "close" ); //弹出对话框 initUserTable(); //绑定表格 } |
iframe层为:
1
2
3
4
|
<!-----------------------弹出的添加用户的对话框-----------------------> <div id= "showRegistUser" > <iframe scrolling= "yes" width= "100%" height= "100%" frameborder= "0" src= "RegistUser.htm" ></iframe> </div> |
然后iframe指向页面的代码也要处理: window.parent.window指等就是我们父页面,然后调用方法即可关闭层!
1
2
3
4
5
|
$.post( "Regist.ashx" , strRequestData, function (data) { if (data == "ok" ) { window.parent.window.afterRegistSuccess(); } }); |
总结
写js代码一定要注意各种细节,其实逻辑不复杂,关键是有些地方少这个少那个,大小写,能否取到ID等等,js好难调试.下面我说下我的调试方式,我一般使用chrome浏览器的开发人员工具来调,这样可以看到很多东西,包括返回的json数据,请求报文返回报文等等,也可以调试JS代码,写JS不难调试难,个人感觉.就拿上面window.parent.window对象,我对这个很抽象,不知道写的对不对,起初写的window.parent,后来运行起来没反应,我就用调试的过程加上个window才调出来,具体如下:
我先找的两个对象..都是window...然后我再找谁有这个afterRegistSuccess方法,结果一看就知道.这个跟VS一样可以设置断点,右上的+号可以添加你想看得元素,如果你js代码有错误,chrome也会帮你指出的,着实强大!总之我们要不仅仅要会写更要出错了知道哪里出错,再改之.下面给出整个前台代码 结合起来看更能理清自己的思路,后台的就不量出来了,就是crud,希望大家共同学习进步!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
<!DOCTYPE html> <head> <meta http-equiv= "Content-Type" content= "text/html; charset=utf-8" /> <title>UserList</title> <link href= "http://www.cnblogs.com/../Content/Css/ui-lightness/jquery-ui-1.8.4.custom.css" rel= "stylesheet" type= "text/css" /> <script> $( function () { //init table $( '#EditUser' ).css( "display" , "none" ); InitUserListByPage(); //innit pagenavagation InitPageNavigation(); $( '#Update' ).click( function () { var JsonData = { Id: $( "#hidden" ).val(), Phone: $( '#PhoneShow' ).val(), LoginName: $( "#LoginNameShow" ).val(), Mail: $( "#MailShow" ).val() } $.get( "UpdateUser.ashx" , JsonData, function (data) { if (data = "true" ) { $( "#EditUser" ).dialog( "close" ); InitUserListByPage(); } }) }) }); //load userList function InitUserListByPage(requestData) { //每次加载先删除再加载 $( '#userListTab tr:gt(0)' ).remove(); //异步请求 $.getJSON( "LoadUserList.ashx" , requestData, function (data) { for (i = 0; i < data.trData.length; i++) { var htmlString = "<tr><td id='ID'>" + data.trData[i].ID + "</td><td id='LoginName'>" + data.trData[i].LoginName + "</td><td id='Phone'>" + data.trData[i].phone + "</td><td id='Mail'>" + data.trData[i].Mail + "</td><td><a href='DeleteUser.ashx?id=" + data.trData[i].ID + "' class='DeleteLink' userId=" + data.trData[i].ID + ">删除</a></td><td><a href='UpdateUser.ashx?id=" + data.trData[i].ID + "' class='UpdateLink' userId=" + data.trData[i].ID + ">添加</a></td><tr>" ; $( '#userListTab' ).append(htmlString); } DeleUser(); Edituser(); }); } //删除用户事件 function DeleUser() { $( '.DeleteLink' ).click( function () { var userId = $( this ).attr( "userId" ); var td = $( this ); if (confirm( "are you sure" )) { $.get( "DeleteUser.ashx" , { id: userId }, function (data) { if (data = "true" ) { td.parent().parent().hide( "slow" ); } else { alert( "Error" ); } }); } return false ; }); } //页面分页 function InitPageNavigation(requestData) { $.getJSON( "LoadUserList.ashx" , requestData, function (data) { var htmlString = data.pageNavigation; $( "#pageNavigation" ).html(htmlString); $( ".pageLink" ).click( function () { var strHref = $( this ).attr( "href" ); strHref = strHref.substring(strHref.lastIndexOf( '?' ) + 1, strHref.length); InitPageNavigation(strHref); InitUserListByPage(strHref); return false ; }) }) } //获得分页标签 function pageNavigation(pageIndex, pageSize, totalCount) { var redirectTo = "" ; var totalPages = Math.max((totalCount + pageSize - 1) / pageSize, 1); var pageNavi; if (totalCount > 1) { if (pageIndex != 1) { pageNavi = "<a class='pageLink' href=" + redirectTo + "?pageIndex=1&pageSize=" + pageSize + "'>首页</a> " ; } if (pageIndex > 1) { pageNavi = "<a class='pageLink' href=" + redirectTo + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "'>上一页</a> " ; } else { } pageNavi = pageNavi + " " ; var currint = 5; for ( var i = 0; i < 10; i++) { if ((pageIndex + i - currint) >= 1 && (pageIndex + i - currint) <= totalPages) { if (currint == i) { pageNavi = pageNavi + "<a class='cpb' href=" + redirectTo + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "'>" + pageIndex + "</a> " ; } else { pageNavi = pageNavi + "<a class='pageLink' href=" + redirectTo + "?pageIndex=" + pageIndex + i - currint + "&pageSize=" + pageSize + "'>" + pageIndex + i - currint + "</a> " ; } } pageNavi = pageNavi + " " ; if (pageIndex < totalPages) { pageNavi = pageNavi + "<a class='pageLink' href=" + redirectTo + "?pageIndex=" + currentPage + 1 + "&pageSize=" + pageSize + "'>下一页</a> " } else { } pageNavi = pageNavi + " " ; if (pageIndex = totalPages) { pageNavi = pageNavi + "<a class='pageLink' href=" + redirectTo + "?pageIndex=" + totalPages + "&pageSize=" + pageSize + "'>末页</a> " } } return pageNavi; } } //注册添加用户事件 function Edituser() { $( '.UpdateLink' ).click( function () { var id = $( this ).attr( 'userId' ); $.getJSON( "GetUserInfoById.ashx" , { id: id }, function (data) { $( "#hidden" ).val(data.ID); $( "#txtShowId" ).text(data.ID); $( "#LoginNameShow" ).val(data.LoginName); $( "#MailShow" ).val(data.Mail); $( '#PhoneShow' ).val(data.phone); }) //$("#hidden").val(id); //$('#txtShowId').text(id); $( "#EditUser" ).dialog({ //设置div为dialog autoOpen: false , title: "注册用户" , height: 400, width: 1000, modal: true }); $( "#EditUser" ).dialog( "open" ); return false ; }) } </script> </head> <body> <table id= "userListTab" > <tr> <th>编号 </th> <th>登录名 </th> <th>电话 </th> <th>邮箱 </th> <th>操作 </th> </tr> </table> <br /> <!--页面分页 --> <div id= "pageNavigation" > </div> <!--修改层--> <div id= "EditUser" > <table> <tr> <td>编号</td> <td> <input type= "hidden" name= "hidden" value= " " id= "hidden" /> <span id= "txtShowId" ></span></td> <td>登录名</td> <td> <input type= "text" name= "LoginNameShow" value= " " id= "LoginNameShow" /></td> <td>电话</td> <td> <input type= "text" name= "PhoneShow" value= " " id= "PhoneShow" /></td> <td>邮箱</td> <td> <input type= "text" name= "MailShow" value= " " id= "MailShow" /> </td> <td colspan= "2" > <input type= "button" name= "Update" value= "Update" id= "Update" /></td> </tr> </table> </div> </body> </html> |