Ajax&jQuery教程总结
目录
第一章 Ajax入门 6
第1讲 传统表单提交存在的问题 6
课程内容 6
1. 问题的引入 6
2. 问题的解决 6
参考进度(0.5课时) 7
第2讲 使用XMLHttpRequest对象 7
课程内容 7
1. 创建XMLHttpRequest对象 7
2. 发送请求 7
3. 接收响应 8
4. 什么是同步、异步? 9
5. 异步请求下接收响应 10
6. 发送POST请求 11
7. JSON响应格式 12
8. JSON格式转换 13
9. 使用Xhr与JSON实现注册前用户名检查 15
10. 什么是Ajax 17
课程案例 17
参考进度(3.5-4课时) 17
第二章 Ajax应用 17
第1讲 通用的发送Xhr请求方法 17
课程内容 17
1. 封装POST方法 17
2. jQuery中的$.get与$.post 19
jQuery.post( url [, data ] [, success ] [, dataType ] ) 19
jQuery.get( url [, data ] [, success ] [, dataType ] ) 20
deferred.done( doneCallbacks [, doneCallbacks ] ) 21
deferred.fail( failCallbacks [, failCallbacks ] ) 21
参考进度 (1-1.5课时) 21
第2讲 省市县联动实例 21
课程内容 21
1. Service和Dao层实现 21
2. Action 实现 22
3. 页面实现 22
课程案例 24
参考进度 (1-1.5课时) 24
第3讲 分页实例 24
课程内容 24
1. Service和Dao实现 24
2. Action实现 25
3. 页面实现 25
课程案例 28
参考进度 (2课时) 28
第三章 jQuery核心 29
第1讲 选择器 29
课程内容 29
id 选择器,格式:("#id") 29
element选择器,格式:("element") 29
class选择器,格式:(".class") 29
descendant (后代)选择器,格式:("ancestor descendant") 29
child(子元素)选择器,格式:("parent>child") 30
:eq(index) 过滤器 30
:first 过滤器 31
:last 过滤器 31
:even 过滤器 31
:odd过滤器 31
包含属性选择器,格式:"[name]" 32
属性值相等选择器,格式:"[name=value]" 32
属性值起始位置匹配选择器,格式:"[name^=value]" 32
属性值结束位置匹配选择器,格式:"[name$=value]" 32
属性值模糊匹配选择器,格式:"[name*=value]" 33
取非选择器,格式:":not(selector)" 33
表单相关选择器 33
参考进度 (1.5课时) 33
第2讲 事件 34
课程内容 34
定义事件:jquery对象.click([eventData], handler) 34
触发事件:jquery对象.click() 34
定义事件:jquery对象.focusin([eventData], handler) 34
定义事件:jquery对象.focusout([eventData], handler) 35
定义事件:jquery对象.mouseenter([eventData], handler) 35
定义事件:jquery对象.mouseleave([eventData], handler) 35
定义事件:$(document).ready(handler) 36
定义事件:parent.on(events [,selector] [,data] ,handler) 36
参考进度 (2课时) 37
第3讲 方法 37
课程内容 37
1. 属性和内容相关方法 38
获取属性值:.attr(attributeName) 38
修改属性值:.attr(attributeName, value) 38
获取属性值:.prop(propertyName) 38
修改属性值:.prop(propertyName, value) 39
获取value属性值:.val() 39
修改属性值:.val(value) 39
获取文本内容:.text() 39
获取HTML内容:.html() 39
设置文本内容:.text(value) 40
设置HTML内容:.html(value) 40
设置HTML内容:.empty() 40
2. 创建元素相关方法 40
创建HTML元素:$(html [, ownerDocument]) 40
建立元素间父子关系:.append(content) 41
建立元素间父子关系:.appendTo(target) 41
3. 元素间导航方法 41
.next([selector]) 41
.prev([selector]) 42
.nextAll([selector]) 42
.prevAll([selector]) 42
.siblings([selector]) 42
.parent([selector]) 42
.parents([selector]) 43
.children([selector]) 43
.find(selector) 43
.each(function) 43
4. 样式相关方法 43
.addClass(className) 44
.removeClass(className) 44
.toggleClass(className) 44
.hasClass(className) 44
5. 特效相关方法 45
.animate(properties [,duration] [,easing] [,complete]) 46
参考进度 (2课时) 46
第四章 jQuery应用 46
第1讲 省市县联动实例 47
课程内容 47
参考进度 (1.5课时) 50
第2讲 分页实例 50
课程内容 50
参考进度 (0.5课时) 52
第3讲 树结构实例 52
参考进度 (1课时) 54
第4讲 AutoComplete实例 54
课程内容 54
参考进度 (2课时) 56
第五章Ajax与jQuery提高 56
第1讲 将分页代码做成jQuery插件 56
课程内容 56
参考进度 (2课时) 61
第一章 Ajax入门
第1讲 传统表单提交存在的问题
课程内容
1. 问题的引入
要开发一个视频网站,给视频播放添加评论功能:
用传统的表单方式在视频播放过程中提交请求,会让页面重新加载,正在播放的动画又回到了起始位置:
打断了用户当前执行的操作,导致体验变差。
2. 问题的解决
可以使用浏览器提供的一个js对象(XMLHttpRequest)来发送请求,它也能够用来发送Http请求,但它的特殊之处在于,它的请求发送不会导致页面跳转(仍保持在当前页面)
参考进度(0.5课时)
第2讲 使用XMLHttpRequest对象
课程内容
1. 创建XMLHttpRequest对象
var xhr = new XMLHttpRequest();
注意:不同浏览器,创建xhr对象方式上有差异:
对于符合W3C标准的浏览器是用上述方法创建xhr对象,对于IE的低版本,使用:
var xhr = ActiveXObject( "Microsoft.XMLHTTP" );
来创建xhr对象,对于IE高版本,也支持new XMLHttpRequest()来创建xhr对象
2. 发送请求
发送请求需要两个方法
- xhr.open("请求方式", uri, true|false);
参数1, 表示请求方式,可以是:get|post|delete|put|head
参数2, 表示请求的目标地址,只能是本域下的地址,跨域需要浏览器支持
参数3, false 同步,true 异步
- xhr.send(请求体内容);
如果是get请求,没有请求体,则参数可以不传或传递null;如果是post请求,则代表请求体内容。请求体内容的格式由请求头中的content-type头设置,常见的格式有:
² application/x-www-form-urlencoded(普通表单提交请求体就是这种格式:参数名=参数值,多个参数间用&分隔)
² multipart/form-data(多部分格式,通常包含文件上传的表单提交时使用这种格式,包括使用xhr2.0提交一个FormData对象,请求体格式也是它)
在刚才的例子上将表单提交按钮改为普通按钮,给普通按钮添加单击事件来发送xhr请求,结果是xhr请求不会导致页面跳转,从而也不会让动画重头播放,关键代码如下:
<script type="text/javascript"> function sendXhr() { var c = document.getElementById("c").value; var xhr = new XMLHttpRequest(); xhr.open("get", "/ajax/commentAction?comment="+c, false); xhr.send(); } </script> <form action="/ajax/commentAction" method="post"> 请输入评论内容:<input type="text" name="comment" id="c"> <input type="button" value="提交" onclick="sendXhr()"> </form> |
3. 接收响应
使用xhr.responseText可以获得文本格式的响应,试一试显示响应内容:
<script type="text/javascript"> function sendXhr() { var c = document.getElementById("c").value; var xhr = new XMLHttpRequest(); xhr.open("get", "/ajax/commentAction?comment="+c, false); xhr.send(); alert(xhr.responseText); } </script> |
会发现,对话框中显示的是请求转发后生成的整个html代码,实际上是不必要的。Servlet代码改动如下:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String comment = request.getParameter("comment"); // 直接返回评论内容即可 response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); out.println(comment); // 写入字符流的响应文本即对应xhr.responseText // 没有必须再次进行请求转发了 // request.getRequestDispatcher("/index.jsp").forward(request, response); } |
注意:xhr默认请求和响应所使用的编码都是UTF-8因此,为了处理简单及一致,页面编码也使用UTF-8
4. 什么是同步、异步?
模拟一下Action不是立刻返回响应的情况:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String comment = request.getParameter("comment"); // 隔了5秒才返回响应 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } // 直接返回评论内容即可 response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); out.println(comment); // 写入字符流的响应文本即对应xhr.responseText // 没有必须再次进行请求转发了 // request.getRequestDispatcher("/index.jsp").forward(request, response); } |
这时的现象是:在发送请求的瞬间,动画停止了,当5秒之后响应返回,动画恢复播放。
引起此现象的原因是xhr.open方法的第三个参数,它的取值是false表示同步请求,含义是接下来的xhr.send方法发送请求会让页面其它部分的代码和操作均陷入等待(阻塞)状态,直到send方法的调用结束(也就是响应返回)后才得以恢复。
接下来,将xhr.open方法的第三个参数由false修改为true,这时代表请求为异步请求。含义是接下来的xhr.send方法发送完请求,就会结束调用,不会让其它部分陷入等待(阻塞)。观察运行结果发现现在发请求确实不会导致页面暂停了,但响应文本无法正确获得了:
<script type="text/javascript"> function sendXhr() { var c = document.getElementById("c").value; var xhr = new XMLHttpRequest(); xhr.open("get", "/ajax/commentAction?comment="+c, true); xhr.send(); alert(xhr.responseText); } </script> |
原因也很好解释,xhr.send方法发送完请求立刻结束,执行下面的xhr.responseText去获取响应文本,但响应是5秒后才返回,因此无法获得内容。
5. 异步请求下接收响应
xhr对象有代表状态的属性readyState:
readyState取值 |
含义 |
0 |
xhr对象刚创建时的初始状态 |
1 |
当请求已发送 |
2 |
响应头已返回 |
3 |
响应解析中 |
4 |
响应完全返回 |
当这些状态发生改变从一个值到另一个值时,会触发一个事件:onreadystatechange
我们比较关心当状态为4时的响应完全返回状态,因此代码可以改变为下:
<script type="text/javascript"> function sendXhr() { var c = document.getElementById("c").value; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 响应完全返回 alert(xhr.responseText); } }; xhr.open("get", "/ajax/commentAction?comment="+c, true); xhr.send(); } </script> |
事件代码应定义在xhr.open方法之前。
6. 发送POST请求
POST请求与GET请求区别在于请求参数的位置处于请求体中而不是跟在请求行后,另外要设置content-type请求头:
<script type="text/javascript"> function sendXhr() { var c = document.getElementById("c").value; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 响应完全返回 alert(xhr.responseText); } }; xhr.open("post", "/ajax/commentAction”, true); xhr.setRequestHeader("content-type”,"application/x-www-form-urlencoded"); xhr.send(”comment="+c); } </script> |
7. JSON响应格式
如果返回纯文本格式的响应,一个回车、换行都可能导致前台js判断的不确定性,并且纯文本格式的响应,只能当作字符串使用,如果要配合前台js做一些逻辑判断、算术运算,不是很方便。
如果返回的是HTML代码直接显示,也是可以的,但HTML代码返回的是“数据+数据的展现方式”,相当于固定了数据的展现方式,不利于重用。
基于以上原因,需要返回支持各种数据类型支持的纯数据格式,并且还需要解析方便,为此引入了JSON格式:所谓JSON就是指符合特定格式的字符串,它能够用来表示多种数据类型,包括数组和对象。
它的基本格式为:
类型 |
格式示例 |
对象 |
{"id": 3, "text": "河北"} |
数组 |
[ {"id": 1, "text":"北京"}, {"id": 2, "text":"天津"}, {"id": 3, "text:"河北"} ] |
字符串类型值 |
"字符串" |
数字类型值 |
123或123.45或1.2345e2 |
布尔类型值 |
true或false |
空值 |
只有null |
注意:JSON对象的属性名,严格的讲,需要两边加双引号;字符串类型,也应当两边加双引号而不能是单引号。
某些js库(如jQuery)在解析JSON时,如果没按照这些规定来,会出现解析错误。
现在用json作为响应格式,通常需要完成以下两步操作:
- java对象转换为json字符串
- json字符串转换为js对象
可以看到,json字符串其实充当了数据的传输载体,或可称为java对象到js对象的桥梁
8. JSON格式转换
首先应当做的是在java代码中将java对象转换为json字符串,并作为响应返回
常用的转换工具包有:
工具包 |
注释 |
json-lib |
老牌的json转换工具 |
gson |
谷歌出品的转换工具,支持泛型,使用相对简单,但由于转换时使用field进行反射,而不是用peroperty(即get,set方法)反射,因此会带来一些处理上的不便 |
jackson |
支持多种方式进行转换:databind(按POJO对象进行转换),stream(按流进行转换),tree(按树进行转换);并且效率上比较高 |
示例代码(gson):
转换实体类: User user = new User("张三", 18, true); String json = new Gson().toJson(user); System.out.println(json); 输出:{"name":"张三","age":18,"sex":true} |
转换实体类List集合: List<User> users = new ArrayList<User>(); users.add(new User("张三", 18, true)); users.add(new User("李四",22, true)); json = new Gson().toJson(users); System.out.println(json); 输出:[{"name":"张三","age":18,"sex":true},{"name":"李四","age":22,"sex":true}] |
转换Map集合: Map<String, String> map = new LinkedHashMap<String, String>(){{ put("a", "苹果"); put("b", "香蕉"); put("c", "李子"); }}; json = new Gson().toJson(map); System.out.println(json); 输出:{"a":"苹果","b":"香蕉","c":"李子"} |
示例代码(jackson,databind模式):
转换实体类: User user = new User("张三", 18, true); ObjectMapper om = new ObjectMapper(); om.writeValue(new OutputStreamWriter(System.out, "gbk"), user); 输出:{"name":"张三","age":18,"sex":true} |
转换实体类List集合: List<User> users = new ArrayList<User>(); users.add(new User("张三", 18, true)); users.add(new User("李四",22, true)); ObjectMapper om = new ObjectMapper(); om.writeValue(new OutputStreamWriter(System.out, "gbk"), users); 输出:[{"name":"张三","age":18,"sex":true},{"name":"李四","age":22,"sex":true}] |
转换Map集合: Map<String, String> map = new LinkedHashMap<String, String>(){{ put("a", "苹果"); put("b", "香蕉"); put("c", "李子"); }}; ObjectMapper om = new ObjectMapper(); om.writeValue(new OutputStreamWriter(System.out, "gbk"), map); 输出:{"a":"苹果","b":"香蕉","c":"李子"} |
其次,在json字符串传递到客户端时,应当将json字符串转换为js对象
转换方法:
方法一: var json = '{"name":"张三", "age": 18, "sex": true, "hobby": ["抽烟", "喝酒"] }'; var object = eval( "(" + json + ")" ); |
方法二: var json = '{"name":"张三", "age": 18, "sex": true, "hobby": ["抽烟", "喝酒"] }'; var object = new Function("return " + json)(); |
jQuery使用的是方法二
9. 使用Xhr与JSON实现注册前用户名检查
Java代码:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); String username = req.getParameter("username"); System.out.println("参数是:" + username); String dbUsername = "zhangsan"; Map<String, Object> map = new HashMap<String, Object>(); if (dbUsername.equals(username)) { map.put("message", "用户名已存在"); map.put("css", "fail"); } else { map.put("message", "用户名可用"); map.put("css", "success"); } // 生成map对应的json字符串 resp.setCharacterEncoding("utf-8"); resp.setContentType("application/json"); String json = new Gson().toJson(map); resp.getWriter().println(json); } |
响应可以设置内容类型为application/json,这样有助于前台js库对响应格式进行判断
页面代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <style type="text/css"> .success {color: green} .fail {color:red} </style> <title>用户注册</title> <script type="text/javascript"> function checkName(username) { //document.getElementById("username").value; //alert(username); var xhr = new XMLHttpRequest(); xhr.onreadystatechange=function(){ if(xhr.readyState == 4) { var span = document.getElementById("usernameSpan"); //alert(xhr.responseText); var json = xhr.responseText; var obj = eval("("+json+")"); span.innerHTML = obj.message; span.className = obj.css; } }; xhr.open("post", "/ajax/checkname"); xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded"); xhr.send("username="+username); } </script> </head> <body> <form action="" method="post"> 用户名:<input type="text" id="username" name="username" onblur="checkName(this.value)"/> <span id="usernameSpan"></span> <br/> 密码:<input type="password" name="pass"/> <br/> 邮箱:<input type="text" name="email"/> <br/> <input type="submit" value="注册"/> </form> </body> </html> |
10. 什么是Ajax
最后来看一下Ajax到底是什么,其实Ajax是几门技术的统称
A Asynchronous 就是指XMLHttpRequest对象能够用来发送不刷新页面的异步请求
j javascript 指操作XMLHttpRequest对象以及处理响应所使用的的语言
a and
x XML 早期的Ajax技术使用XML作为响应格式。但XML响应生成和解析不便,逐渐为更轻便的JSON格式所代替
课程案例
见ajax项目下代码
参考进度(3.5-4课时)
第二章 Ajax应用
第1讲 通用的发送Xhr请求方法
课程内容
1. 封装POST方法
观察Xhr发送请求和接收响应的代码,看是否有能够重用的地方:
发现:
1.每次请求地址不同;
2.每次请求参数不同;
3.每次拿到响应后,处理的方式不同
所以可以抽取一个通用的发送POST请求方法,参数1为请求地址,参数2为请求参数,对于第三点,处理响应的代码会有多条,因此想到可以将多条操作代码放在一个函数中当作参数3,代码如下:
/* 参数1: 代表请求地址 参数2:请求请求参数字符串 参数3:是一个函数,会在响应返回时被执行,这个函数称为回调(callback)函数 */ function post(url, params, fn) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState==4){ // 将响应json字符串转换为js对象 var obj = eval("("+xhr.responseText+")"); fn(obj); // 调用回调函数,参数为转换好的js对象 } }; xhr.open("post", url, true); xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded"); xhr.send(params); } /* 而调用代码则变得简单,用它来改写上节课的注册器用户名检查例题如下 */ <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <style type="text/css"> .success {color: green} .fail {color:red} </style> <title>用户注册</title> <script type="text/javascript" src="/ajax/day2/ajax.js"></script> <script type="text/javascript"> function checkName(username) { /* 封装后,发送POST请求和处理响应变得简洁易懂 */ post("/ajax/checkname", "username="+username, function(obj){ var span = document.getElementById("usernameSpan"); span.innerHTML = obj.message; span.className = obj.css; }); } </script> </head> <body> <form action="" method="post"> 用户名:<input type="text" id="username" name="username" onblur="checkName(this.value)"/> <span id="usernameSpan"></span> <br/> 密码:<input type="password" name="pass"/> <br/> 邮箱:<input type="text" name="email"/> <br/> <input type="submit" value="注册"/> </form> </body> </html> |
同理可以封装GET方法
2. jQuery中的$.get与$.post
jQuery是一套js库,用来简化js代码。可以不夸张的说,jQuery改变了程序员对js的偏见,也改变了众多程序员书写js代码的习惯。它提供了更为强大的Ajax相关方法:
jQuery.post( url [, data ] [, success ] [, dataType ] ) |
||
参数名 |
参数类型 |
说明 |
url |
String |
请求地址 |
data |
简单对象或String |
请求参数 |
success |
Function(data, textStatus, jqXHR) |
成功时的回调函数 参数1:数据,根据响应类型而定,可以是xml 、json、html、text等 参数2:响应状态文本 参数3:jQuery封装后的Xhr对象 |
dataType |
String |
期望服务器返回的数据格式:xml,script,json,html,text |
使用例子:
/* 发送请求,但忽略响应 */ $.post( "test.action" ); /* 发送请求,带请求参数(方式一),仍然忽略响应 */ $.post( "test.action", "name=John&time=2pm"); 参数:name=John&time=2pm /* 发送请求,带请求参数(方式二),仍然忽略响应 */ $.post( "test.action", { name: "John", time: "2pm" } ); 参数:name=John&time=2pm /* 发送请求,带数组请求参数,仍然忽略响应 */ $.post( "test.action", { 'choices[]': [ "Jon", "Susan" ] } ); 参数:choices[]=Jon&choices[]=Susan /* 发送请求,请求参数从form表单中取,仍然忽略响应 */ <form action="aaa.jsp" method="post" id="myform"> <input type="text" name="username" value="zhangsan"> <input type="password" name="password" value="123"> <input type="checkbox" name="hobby" value="唱歌" checked> <input type="checkbox" name="hobby" value="游泳"> <input type="checkbox" name="hobby" value="跳舞"> </form> $.post( "test.action", $( "#myform" ).serialize() ); 参数:username=zhangsan&password=123&hobby=%E5%94%B1%E6%AD%8C 注意:%E5%94%B1%E6%AD%8C即代表唱歌这两个汉字,使用了utf-8编码 /* 发送请求,带请求参数,使用回调函数接受响应 */ $.post( "/ajax/checkname", { username: "John"}, function(json){ console.log(json.message); } ); 假设服务器返回为json字符串:{"message":"用户名可用","css":"success"} 输出:用户名可用 /* 发送请求,带请求参数,使用Deffered接口接受响应 */ $.post("/ajax/checkname", {username:"John"}).done(function(json){ console.log(json.message) }); 假设服务器返回为json字符串:{"message":"用户名可用","css":"success"} 输出:用户名可用 |
对应get请求也有相应的封装:
jQuery.get( url [, data ] [, success ] [, dataType ] ) |
||
参数名 |
参数类型 |
说明 |
url |
String |
请求地址 |
data |
简单对象或String |
请求参数 |
success |
Function(data, textStatus, jqXHR) |
Ajax成功时的回调函数 参数1:数据,根据响应类型而定,可以是xml 、json、html、text等 参数2:响应状态文本 参数3:jQuery封装后的Xhr对象 |
dataType |
String |
期望服务器返回的数据格式:xml,script,json,html,text |
无论对于post方法还是get方法,它们返回的都是Deffered接口类型,它的常见方法如下:
deferred.done( doneCallbacks [, doneCallbacks ] ) |
||
参数名 |
参数类型 |
说明 |
doneCallbacks |
Function(data, textStatus, jqXHR) |
Ajax成功时的回调函数 参数1:数据,根据响应类型而定,可以是xml 、json、html、text等 参数2:响应状态文本 参数3:jQuery封装后的Xhr对象 |
deferred.fail( failCallbacks [, failCallbacks ] ) |
||
参数名 |
参数类型 |
说明 |
failCallbacks |
Function(jqXHR, textStatus, errorThrown) |
Ajax失败的回调函数 参数1:jQuery封装后的Xhr对象 参数2:错误文本描述,可能是 timeout 超时 error Http错误 abort 取消 parseerror 解析错误 当是Http错误发生时,参数3表示具体的Http错误文本,例如Not Found等 |
Deffered接口是jQuery1.5加入,可以根据自己的习惯选择使用。
参考进度 (1-1.5课时)
第2讲 省市县联动实例
课程内容
1. Service和Dao层实现
提供了一张城市表,包括了三级城市数据
昨天的作业要求学员完成城市查询的Service和Dao部分
主要用到的查询语句如下:
/* 查询所有一级城市 */ "select * from cities where parentid is null order by id"; /* 根据父城市id,查询下属的二、三级城市 */ "select * from cities where parentid = ? order by id"; |
2. Action 实现
/* url-pattern: /findSheng */ public class FindShengAction extends HttpServlet { private CityService cityService = new CityServiceImpl(); protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { List<City> list = cityService.findSheng(); String json = new Gson().toJson(list); resp.setCharacterEncoding("utf-8"); resp.setContentType("application/json"); resp.getWriter().print(json); } } /* url-pattern: /findCity */ public class FindCityAction extends HttpServlet { private CityService cityService = new CityServiceImpl(); protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); String pid = req.getParameter("pid"); List<City> list = cityService.findCity(Integer.parseInt(pid)); String json = new Gson().toJson(list); resp.setCharacterEncoding("utf-8"); resp.setContentType("application/json"); resp.getWriter().print(json); } } |
3. 页面实现
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <style type="text/css"> .se { width: 120px; } </style> <script type="text/javascript" src="/ajax/js/jquery-1.11.1.js"></script> <script type="text/javascript"> function createOptions(list, parent) { for(var i = 0; i < list.length; i++){ //alert(json[i].name); // 谷歌,火狐或ie8+ 提供了:window.console 可以在浏览器控制台打印调试信息 //console.log(json[i].name); // 动态生成:<option>北京</option> var option = document.createElement("option"); option.innerHTML = list[i].name; option.value = list[i].id; // 建立父子关系 parent.appendChild(option); } } window.onload=function(){ $.get("/ajax/findSheng", {}, function(list){ var sheng = document.getElementById("sheng"); createOptions(list, sheng); // 主动触发onchange事件 =》 调用该事件对应的函数 sheng.onchange(); }); } function shengchange(parentId) { $.get("/ajax/findCity", {pid:parentId}, function(list){ var shi = document.getElementById("shi"); shi.innerHTML = ""; // 清空旧内容 createOptions(list, shi); shi.onchange(); }); } function shichange(parentId) { $.get("/ajax/findCity", {pid:parentId}, function(list){ var xian = document.getElementById("xian"); xian.innerHTML = ""; // 清空旧内容 createOptions(list, xian) }); } </script> </head> <body> 省(直辖市)<select id="sheng" onchange="shengchange(this.value)" class="se"> </select> 市<select id="shi" onchange="shichange(this.value)" class="se"></select> 区县<select id="xian" class="se"></select> </body> </html> |
这里要讲解的要点如下:
- 向学员强调,Action测试成功,返回的json数据正确,再写js代码
- 如何利用浏览器提供的console对象来打印js对象以方便调试(建议使用Chrome或带firebug插件的火狐浏览器)
- 动态生成option,为option的value和内容赋值,建立select与option的父子关系(复习)
- 对于改变省时加载市的数据,如何获取当前省id
- 代码的执行顺序(ajax部分)
- 如何清空select中旧的option
- 如何联动(主动触发onchange事件)
- 最后再抽取createOptions函数来减少重复代码
课程案例
见ajax项目中WebRoot下day2内容
参考进度 (1-1.5课时)
第3讲 分页实例
课程内容
1. Service和Dao实现
关键代码如下:
/* 其中index代表页码,从1开始;pagesize代表每页有多少条记录 */ String sql = "select b.* from (select rownum r, a.* from (select * from cities order by id) a where rownum <= ?) b where r > ?"; conn = JdbcUtil.getConnection(); psmt = conn.prepareStatement(sql); psmt.setInt(1, pagesize*index); psmt.setInt(2, pagesize*(index-1)); rs = psmt.executeQuery(); |
2. Action实现
/* url-pattern: /findCityPage */ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 接收页码和页面大小请求参数 int index = Integer.parseInt(req.getParameter("index")); int pagesize = Integer.parseInt(req.getParameter("pagesize")); // 查询本页记录 List<City> list = cityService.findCityByPage(index, pagesize); // 查询总记录数 int count = cityService.findCount(); // 计算总页数 int total = 0; if(count % pagesize == 0) { total = count/pagesize; } else { total = count/pagesize + 1; } // 将返回信息统一放入map中 Map<String, Object> map = new HashMap<String, Object>(); map.put("total", total); map.put("list", list); // 将map转换为json字符串 Gson gson = new GsonBuilder().setPrettyPrinting().create(); String json = gson.toJson(map); // 将json字符串写入响应 resp.setCharacterEncoding("utf-8"); resp.setContentType("application/json"); resp.getWriter().print(json); } |
3. 页面实现
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <script type="text/javascript" src="/ajax/js/jquery-1.11.1.js"></script> <script type="text/javascript"> $(function(){ var pagesizeSelect = document.getElementById("pagesize"); pagesizeSelect.onchange = function() { loadpage(1); }; function createTbody(map) { var tbody = document.getElementById("tbody"); tbody.innerHTML = ""; for(var i = 0;i < map.list.length;i++){ var tr = document.createElement("tr"); var td0 = document.createElement("td"); var td1 = document.createElement("td"); var td2 = document.createElement("td"); td0.innerHTML = i+1; td1.innerHTML = map.list[i].id; td2.innerHTML = map.list[i].name; tr.appendChild(td0); tr.appendChild(td1); tr.appendChild(td2); tbody.appendChild(tr); } } function createA(index, text) { var a = document.createElement("a"); a.innerHTML = text; a.href = "javascript:void(0)"; a.onclick = function() { loadpage(index); } return a; } function createSpan(text) { var span = document.createElement("span"); span.innerHTML = text; return span; } function createPager(map, index) { var pager = document.getElementById("pager"); pager.innerHTML = ""; var first = (index>1)?createA(1, "首页"):createSpan("首页"); var prev = (index>1)?createA(index-1, "上一页"):createSpan("上一页"); var next = (index<map.total)?createA(index+1, "下一页"):createSpan("下一页"); var last = (index<map.total)?createA(map.total, "终页"):createSpan("终页"); pager.appendChild(first); pager.appendChild(createSpan(" ")); pager.appendChild(prev); pager.appendChild(createSpan(" ")); // 计算页号的范围,参考了百度的实现 var begin, end; if(map.total <= 10) { begin = 1; end = map.total; } else { if(index <= 6) { begin = 1; end = 10; } else { if(map.total - index <= 4) { begin = map.total - 9; end = map.total; } else { begin = index - 5; end = index + 4; } } } for(var i = begin ; i <= end; i++) { var page = (i == index)?createSpan(i):createA(i, i); pager.appendChild(page); pager.appendChild(createSpan(" ")); } pager.appendChild(next); pager.appendChild(createSpan(" ")); pager.appendChild(last); } function loadpage(index) { $.get("/ajax/findCityPage", {index:index,pagesize:pagesizeSelect.value}, function(map){ createTbody(map); createPager(map, index); }); } loadpage(1); }); </script> </head> <body> <!-- 实现局部刷新(ajax)的分页 --> <table width="100%" border="1"> <thead> <tr> <th>序号</th> <th>id</th> <th>name</th> </tr> </thead> <tbody id="tbody"></tbody> </table> <div id="pager"></div> <select id="pagesize"> <option value="10" selected>每页10条</option> <option value="20">每页20条</option> <option value="50">每页50条</option> <option value="100">每页100条</option> </select> </body> </html> |
关于计算中间页码的逻辑参考如下:
对于前六页都一样 begin=1,end=10 从第7页开始,满足begin=index-5,end=index+4的规律 ... 对于最后四页,满足begin=total-9,end=total 344 345 346 347 348 349 350 351 352 353 344 345 346 347 348 349 350 351 352 353 |
课程案例
参考进度 (2课时)
第三章 jQuery核心
第1讲 选择器
课程内容
id 选择器,格式:("#id") |
|
示例 |
说明 |
<input type="button" value="按钮" id="btn"/> $("#btn").css("color", "red"); |
根据id属性查找元素 |
element选择器,格式:("element") |
|
示例 |
说明 |
<p>段落1</p> <p>段落2</p> $("p").css("color", "red"); |
根据元素(标签名称)查找元素 |
class选择器,格式:(".class") |
|
示例 |
说明 |
<p>段落1</p> <p class="a">段落2</p> $(".a").css("color", "red"); |
根据class属性查找元素 |
href="http://api.jquery.com/descendant-selector/" title="Permalink to Descendant Selector (\“ancestor descendant\”)" descendant (后代)选择器,格式:("ancestor descendant") |
|
示例 |
说明 |
<p>段落1</p> <p class="a">段落2</p> <div id="d1"> <p>段落3</p> <center> <p>段落4</p> <p>段落5</p> </center> </div> $("div p").css("color", "red"); |
根据给定的祖先元素,找到所有匹配的后代元素 |
child(子元素)选择器,格式:("parent>child") |
|
示例 |
说明 |
<p>段落1</p> <p class="a">段落2</p> <div id="d1"> <p>段落3</p> <center> <p>段落4</p> <p>段落5</p> </center> </div> $("div>p").css("color", "red"); |
根据给定的父元素,找到所有匹配的子元素 |
:eq(index) 过滤器 |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a:eq(0)").css("color", "red"); |
按照下标进行过滤,下标从0开始,jquery1.8版本后支持负数,-1表示最后一个元素,-2表示倒数第二个元素... |
:first 过滤器 |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a:first").css("color", "red"); |
等价于:eq(0) |
:last 过滤器 |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a:last").css("color", "red"); |
找到最后一个元素 |
:even 过滤器 |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a:even").css("color", "red"); |
过滤偶数元素,注意所谓奇偶,是根据下标而言 |
:odd过滤器 |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a:odd").css("color", "red"); |
过滤奇数元素,注意所谓奇偶,是根据下标而言 |
包含属性选择器,格式:"[name]" |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a[title]").css("color", "red"); |
查找包含某一name属性的元素 |
属性值相等选择器,格式:"[name=value]" |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a[title=tb2]").css("color", "red"); |
查找包含某一name属性的元素,且值等于value |
属性值起始位置匹配选择器,格式:"[name^=value]" |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a[title^=t]").css("color", "red"); |
查找包含某一name属性的元素,且其起始位置的值等于value |
属性值结束位置匹配选择器,格式:"[name$=value]" |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a[title$=2]").css("color", "red"); |
查找包含某一name属性的元素,且其结束位置的值等于value |
属性值模糊匹配选择器,格式:"[name*=value]" |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a[title*=b]").css("color", "red"); |
查找包含某一name属性的元素,只要其值的一部分等于value |
取非选择器,格式:":not(selector)" |
|
示例 |
说明 |
<a href="aaa" title="tb1">链接1</a> <a href="aaa" >链接2</a> <a href="aaa" title="tb2">链接3</a> <a href="aaa" title="sb2">链接4</a> $("a:not([title*=b])").css("color", "red"); |
对另一个selector选择器取非 |
表单相关选择器 |
|
示例 |
说明 |
$(":input") |
找到所有input |
$(":button") |
找到所有按钮 |
$(":checkbox") |
找到所有复选框 |
$(":radio") |
找到所有单选按钮 |
$(":file") |
找到所有文件选择器 |
$(":text") |
找到所有文本框 |
$(":password") |
找到所有密码框 |
$(":reset") |
找到所有重置按钮 |
$(":submit") |
找到所有提交按钮 |
$(":select") |
找到所有下列列表框 |
$(":enabled") |
找到所有启用元素 |
$(":disabled") |
找到所有禁用元素 |
$(":checked") |
找到所有选中的单选按钮或复选框 |
参考进度 (1.5课时)
第2讲 事件
课程内容
定义事件:jquery对象.click([eventData], handler) |
||
参数名 |
参数类型 |
说明 |
eventData |
任意类型 |
可以通过eventObject.data来获取 |
handler |
Function(Event eventObject) |
事件处理函数 eventObject为事件对象 |
示例 |
说明 |
|
$(":button").click(function(){ alert("OK"); }); |
给所有按钮添加单击事件 |
|
$(":button").click(123, function(e){ alert(e.data); }); |
给所有按钮添加单击事件,弹出对话框显示123 |
触发事件:jquery对象.click() |
||
参数名 |
参数类型 |
说明 |
主动触发对象的单击事件 |
注意:
² 在事件处理函数中,this即为dom对象
² dom对象要转换为jQuery对象的方法为$(dom对象) 返回jQuery对象
² jQuery对象其实可以看作一个数组,可以通过size()或length属性得到数组大小
其它很多事件与click类似:就不一个个说明了,仅说明jquery中特有的事件
定义事件:jquery对象.focusin([eventData], handler) |
||
参数名 |
参数类型 |
说明 |
eventData |
任意类型 |
可以通过eventObject.data来获取 |
handler |
Function(Event eventObject) |
事件处理函数 eventObject为事件对象 |
示例 |
说明 |
|
<p><input type="text"> <span>focusin fire</span></p> $( "p" ).focusin(function() { $( this ) .find( "span" ) .css( "display", "inline" ) .fadeOut( 1000 ); }); |
focusin类似于focus获得焦点事件,但不同之处它支持事件冒泡,此例中,事件是加在父元素之上,而不是象focus必须将事件加在文本框上 |
定义事件:jquery对象.focusout([eventData], handler) |
||
参数名 |
参数类型 |
说明 |
eventData |
任意类型 |
可以通过eventObject.data来获取 |
handler |
Function(Event eventObject) |
事件处理函数 eventObject为事件对象 |
示例 |
说明 |
|
<p><input type="text"> <span>focusout fire</span></p> $( "p" ).focusout(function() { $( this ) .find( "span" ) .css( "display", "inline" ) .fadeOut( 1000 ); }); |
focusout类似于blur失去焦点事件,但不同之处它支持事件冒泡,此例中,事件是加在父元素之上,而不是象blur必须将事件加在文本框上 |
定义事件:jquery对象.mouseenter([eventData], handler) |
||
参数名 |
参数类型 |
说明 |
eventData |
任意类型 |
可以通过eventObject.data来获取 |
handler |
Function(Event eventObject) |
事件处理函数 eventObject为事件对象 |
示例 |
说明 |
|
鼠标移入事件,与mouseover不同之处在于 如果当前元素有子元素存在时,则从当前元素移动到子元素会触发mouseover事件,而不会触发mouseenter事件 |
定义事件:jquery对象.mouseleave([eventData], handler) |
||
参数名 |
参数类型 |
说明 |
eventData |
任意类型 |
可以通过eventObject.data来获取 |
handler |
Function(Event eventObject) |
事件处理函数 eventObject为事件对象 |
示例 |
说明 |
|
<div id="tip" style="width:100px;height:20px;position: absolute;color:white;display: none;"></div> <a class="tip" href="#" title="提示信息"> 超链接 <span style="color:black">其他部分</span> </a> $(".tip") .mouseover(function(){ var pos = $(this).position(); $("#tip") .html(this.title) .css({top:pos.top-20, left:pos.left+$(this).width()}) .show(300); }) .mouseout(function(){ $("#tip").hide(300); }); |
鼠标移出事件,与mouseout不同之处在于 如果当前元素有子元素存在时,则从子元素元素移动到当前元素会触发mouseout事件,而不会触发mouseleave事件 示例说明: <a>标签中有一个<span>标签,现在希望实现功能:鼠标移入超链接显示div提示,移出超链接隐藏div提示. 如果使用mouseover和mouseout来实现,会发现提示div不断闪烁的现象,原因拿mouseout来解释:从<a>移动到它的子标签<span>时也会触发mouseout事件导致隐藏;所以如果不希望<a>移动到<span>时隐藏div,需要将mouseout替换为mouseleave;同理,需要将mouseover替换为mouseenter |
定义事件:$(document).ready(handler) |
||
参数名 |
参数类型 |
说明 |
handler |
Function() |
事件处理函数 |
示例 |
说明 |
|
$(document).ready(function(){ // dom加载完成后的初始化代码 }); 等价方式: $(function(){ // dom加载完成后的初始化代码 }); |
在DOM树完全加载时触发,可以用来取代传统的window.onload事件,他们是不同的:window.onload事件不仅要等到DOM树完全加载,还需要等待所有外部资源(如图片,外部css,其他js文件)完全加载完毕后才触发 |
定义事件:parent.on(events [,selector] [,data] ,handler) |
||
参数名 |
参数类型 |
说明 |
events |
String |
一或多个以空格分隔的事件名称 |
selector |
String |
一个用于过滤后代元素的选择器,事件触发时,事件函数会在这些匹配的后代元素上被调用;如果省略此参数,事件函数仅会在parent上被调用 |
data |
任意类型 |
可以通过eventObject.data来获取 |
handler |
Function(Event eventObject) |
事件处理函数 eventObject为事件对象 |
示例 |
说明 |
|
<input type="button" value="按钮" id=”btn”/> $("#btn").on("click", function(){ // 执行一些操作 }); |
省略了选择器参数,相当于将事件函数直接绑定在#btn上,等价于 $("#btn”).click(function(){ // 执行一些操作 }); |
|
<div id="d"> <input type="button" value="按钮" class="btn"/> </div> $("#d").on("click", ".btn", function(){ // 执行一些操作 }); |
在父元素#d上调用on方法,而使用选择器去过滤其中的按钮元素,最后的效果是事件函数在按钮点击时被触发。原理是利用了事件冒泡的机制,这种做法被称之为事件委托(delegate) 事件委托的好处是,事件不是真正加在内部元素上,由此带来影响:即使内部元素是动态生成的,也能触发该事件。如果不用事件委托而是将事件直接绑定到元素,那么要求该元素必须已存在,而不能是动态生成的 |
对于事件对象的说明,jquery封装了事件对象,保证事件对象属性和方法的浏览器兼容性,比较有用的事件对象的属性和方法有:
属性或方法名称 |
说明 |
.preventDefault() |
用来阻止事件的默认行为,可以用来控制如超链接不跳转、表单不提交等 另一种阻止默认行为的方法是在事件处理函数中return false |
.stopPropagation() |
用来阻止事件冒泡 |
.pageX |
鼠标的X坐标,相对于文档的左边缘 |
.pageY |
鼠标的Y坐标,相对于文档的上边缘 |
.originalEvent |
访问原始的事件对象 |
参考进度 (2课时)
第3讲 方法
课程内容
jQuery的大部分方法支持链式调用,因为在每个方法内部返回的是jQuery对象本身
1. 属性和内容相关方法
获取属性值:.attr(attributeName) |
||
参数名 |
参数类型 |
说明 |
attributeName |
String |
属性名 |
示例 |
说明 |
|
<img src="1.jpg/> $("img").attr("src"); |
获取图片的src属性值 |
修改属性值:.attr(attributeName, value) |
||
参数名 |
参数类型 |
说明 |
attributeName |
String |
属性名 |
value |
String or Number |
属性值 |
示例 |
说明 |
|
<img src="1.jpg/> $("img").attr("src", "2.jpg"); |
修改图片的src属性值 |
获取属性值:.prop(propertyName) |
||
参数名 |
参数类型 |
说明 |
propertyName |
String |
属性名 |
示例 |
说明 |
|
<input type="checkbox checked/> $(":checkbox").prop("checked"); |
获取复选框的属性值 结果为true 如果使用 $(":checkbox").attr("checked"); 结果为checked(字符串) 如果checked属性不存在,则prop方法返回false,而attr方法返回undefined prop方法在jQuery 1.6加入,jQuery推荐在获取和设置如:checked, disabled, selected这些属性时使用prop 而非attr,用attr方法只是判断这几种属性是否存在,换句话说,只是检查他们在页面上的初始值。 |
修改属性值:.prop(propertyName, value) |
||
参数名 |
参数类型 |
说明 |
propertyName |
String |
属性名 |
value |
Boolean |
属性值 |
示例 |
说明 |
|
<input type="checkbox" checked/> $(":checkbox").prop("checked", false); |
修改复选框的状态 |
获取value属性值:.val() |
||
参数名 |
参数类型 |
说明 |
示例 |
说明 |
|
<input type="text" value="zhangsan"/> $(":text").val(); |
获取文本框的value属性值 |
修改属性值:.val(value) |
||
参数名 |
参数类型 |
说明 |
value |
String or Array |
属性值 |
示例 |
说明 |
|
<input type="text" value="zhangsan"/> $(":text").val("lisi"); |
修改文本框的value属性值 |
|
<input type="checkbox" value="唱歌"/> <input type="checkbox" value="跳舞"/> <input type="checkbox" value="学习"/> $(":checkbox").val(["唱歌", "学习"]); |
执行结果会让第一,三个复选框被选中 还可以用来设置<select multiple>中的多选值 |
获取文本内容:.text() |
||
参数名 |
参数类型 |
说明 |
示例 |
说明 |
|
<p>a, <b>c</b></p> $("p").text(); |
获取标签之间的文本内容,会剥除内部的html标签,结果为:a, c |
获取HTML内容:.html() |
||
参数名 |
参数类型 |
说明 |
示例 |
说明 |
|
<p>a, <b>c</b></p> $("p").html(); |
获取标签之间的HTML内容, 结果为:a, <b>c</b> |
设置文本内容:.text(value) |
||
参数名 |
参数类型 |
说明 |
value |
String |
文本值 |
示例 |
说明 |
|
<p></p> $("p").text("<b>c</b>"); |
修改标签之间的文本内容,html标签会转为相应的实体显示,结果为: <b>c</b> |
设置HTML内容:.html(value) |
||
参数名 |
参数类型 |
说明 |
value |
String |
文本值 |
示例 |
说明 |
|
<p></p> $("p").html("<b>c</b>"); |
修改标签之间的HTML内容,结果为: <b>c</b> 相当于dom对象.innerHTML="<b>c</b>"; |
设置HTML内容:.empty() |
||
参数名 |
参数类型 |
说明 |
示例 |
说明 |
|
<select> <option>北京</option> <option>上海</option> <option>天津</option> </select> $("select").empty(); |
清除标签之间所有内容 |
2. 创建元素相关方法
创建HTML元素:$(html [, ownerDocument]) |
||
参数名 |
参数类型 |
说明 |
html |
htmlString |
要创建的HTML内容,可以是一个空标签,也可以嵌套其他HTML内容 如果是空标签,jQuery使用document.createElement()创建该元素;如果HTML字符串中添加了属性,或是包含了子标签,jQuery使用.innerHTML来创建内部元素 |
ownerDocument |
document |
新创建的HTML内容所从属的文档对象 |
示例 |
说明 |
|
$("<span>") |
创建一个span元素 |
|
$("<span>test</span>") |
创建span元素并同时指定内容 |
|
$("<span>test<b>aaa</b></span>") |
创建span元素并同时指定其中的html内容 |
建立元素间父子关系:.append(content) |
||
参数名 |
参数类型 |
说明 |
content |
htmlString 或 dom对象 或 jQuery对象 |
父元素追加content作为子元素 |
示例 |
说明 |
|
$("body").append("<span>test</span>"); |
为body创建并追加一个span元素(htmlString) |
|
var dom = document.createElement("span"); span.innerHTML = "test"; $("body").append(dom); |
为body创建并追加一个span元素(dom对象) |
|
$("body").append($("<span>test</span>")); |
为body创建并追加一个span元素(jQuery对象) |
建立元素间父子关系:.appendTo(target) |
||
参数名 |
参数类型 |
说明 |
target |
Selector 或 dom对象 或 jQuery对象 |
子元素追加到父元素 |
示例 |
说明 |
|
$("<span>test</span>").appendTo("body"); |
创建一个span元素并追加到body(选择器) |
|
$("<span>test</span>").appendTo( document.getElementById("bodyId") ); |
创建一个span元素并追加到body(dom对象) |
|
$("<span>test</span>").appendTo($("body")); |
创建一个span元素并追加到body(jQuery对象) |
3. 元素间导航方法
.next([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到下一个兄弟元素 加了选择器,找到下一个符合选择器的兄弟元素 |
.prev([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到上一个兄弟元素 加了选择器,找到上一个符合选择器的兄弟元素 |
.nextAll([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到后面所有兄弟元素 加了选择器,找到后面所有符合选择器的兄弟元素 |
.prevAll([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到前面所有兄弟元素 加了选择器,找到前面所有符合选择器的兄弟元素 |
.siblings([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到所有兄弟元素 加了选择器,找到所有符合选择器的兄弟元素 |
.parent([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到父元素 加了选择器,找到符合选择器的父元素 |
.parents([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到所有祖先元素 加了选择器,找到符合选择器的所有祖先元素 |
.children([selector]) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
不加选择器,找到所有孩子元素 加了选择器,找到符合选择器的所有孩子元素 |
.find(selector) |
||
参数名 |
参数类型 |
说明 |
selector |
Selector |
选择器 |
示例 |
说明 |
|
加了选择器,找到符合选择器的所有后代元素 |
.each(function) |
||
参数名 |
参数类型 |
说明 |
function |
Function(Integer i, Element element) |
用来遍历jQuery对象,每次循环,都会回调function函数 index参数:循环变量,从0开始 element参数:每次循环,第i个元素对应的dom对象 一般来讲,不需要调用each来对jQuery对象中每个元素进行显式遍历 |
示例 |
说明 |
|
4. 样式相关方法
.addClass(className) |
||
参数名 |
参数类型 |
说明 |
className |
String |
要添加的样式名 className 可以是用空格分隔的多个样式 |
示例 |
说明 |
|
.removeClass(className) |
||
参数名 |
参数类型 |
说明 |
className |
String |
要移除的样式名 className 可以是用空格分隔的多个样式 |
示例 |
说明 |
|
.toggleClass(className) |
||
参数名 |
参数类型 |
说明 |
className |
String |
要切换的样式名 className 可以是用空格分隔的多个样式 |
示例 |
说明 |
|
.hasClass(className) |
||
参数名 |
参数类型 |
说明 |
className |
String |
判断是否有className样式 |
示例 |
说明 |
|
获取宽度方法:
.width()
.innerWidth()
.outerWidth()
区别如下:
类似的,获取高度方法:
.height()
.innerHeight()
.outerHeight()
区别如下:
.position() 与.offset()
它们都是返回一个坐标对象{"top": y坐标值, "left": x坐标值},区别在于position返回的是相对于父元素的坐标,而offset返回的是相对于document的坐标
5. 特效相关方法
.show()
.hide()
.toggle()
用来控制元素的显示、隐藏、切换显示隐藏,它们都可以接收一个整数参数(单位毫秒)来控制特效的运行时间,无参表示没有特效,另外两组特效函数只是在特效动画上与之不同:
第一组:
.slideDown() 显示
.slideUp() 隐藏
.slideToggle() 切换显示隐藏
第二组:
.fadeIn() 显示
.fadeOut() 隐藏
.fadeToggle() 切换显示隐藏
如果需要用到自定义动画效果,使用.animate()方法:
.animate(properties [,duration] [,easing] [,complete]) |
||
参数名 |
参数类型 |
说明 |
properties |
PlainObject |
一组css属性组成的简单对象, 表示动画结束时要达到的样式 |
duration |
String或Number |
Number:执行动画效果的时间(单位毫秒) String: fast 等价于200毫秒 slow 等价于600毫秒 |
easing |
String |
动画效果变换中的加速度控制 swing 默认效果(越来越快) linear 线性变化(无加速度) |
complete |
Function |
动画完毕后的回调函数 |
示例 |
说明 |
|
参考进度 (2课时)
第四章 jQuery应用
第1讲 省市县联动实例
课程内容
第二章省市县联动页面部分使用jQuery改写如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <style type="text/css"> .se { width: 120px; } </style> <script type="text/javascript" src="/ajax/js/jquery-1.11.1.js"></script> <script type="text/javascript" src="/ajax/day2/ajax.js"></script> <script type="text/javascript"> function createOptions(list, parent){ parent.empty(); for(var i = 0; i < list.length; i++){ var c = list[i]; var op = $("<option>").html(c.name).val(c.id).appendTo(parent); } } $(function(){ var sheng = $("#sheng"); var shi = $("#shi"); var xian = $("#xian"); $.get("/ajax/findSheng", function(list){ createOptions(list, sheng); sheng.change(); }); sheng.change(function(){ $.get("/ajax/findCity", {pid: $(this).val()}, function(list){ createOptions(list, shi); shi.change(); }); }); shi.change(function(){ $.get("/ajax/findCity", {pid: $(this).val()}, function(list){ createOptions(list, xian); }); }); }); </script> </head> <body> 省(直辖市)<select id="sheng" class="se"></select> 市<select id="shi" class="se"></select> 区县<select id="xian" class="se"></select> </body> </html> |
提高:可以利用缓存来减少页面与服务器的交互次数
缓存实现:
function cache() { var firstLevelCache = {}; var fns = { put:function(key, value){ firstLevelCache[key] = value; // 如果支持本地存储,可以进一步利用,避免页面切换或关闭时,仍然要访问服务器 if(window.localStorage) { // 本地存储中的变量值只支持字符串,因此需要将js对象转换为json字符串后存储 window.localStorage[key] = JSON.stringify(value); } }, get:function(key){ // 首先查询firstLevelCache var value = firstLevelCache[key]; // 如果没查到,进一步查询本地存储 if(!value && window.localStorage) { var v = window.localStorage[key]; if(v) { // 如果本地存储中存在,则将存储的json字符串转回js对象 value = new Function("return " + v)(); firstLevelCache[key] = value; } } return value; } }; /* 这里返回的是一个对象,它内嵌了get,put方法 它们能够引用函数内的局部变量firstLevelCache firstLevelCache对外是不可见的,但它对于get,put方法来言仍是全局的 这种做法是js中避免全局变量污染的一种手段 */ return fns; } |
用法:存数据cache().put(key, value),取数据cache().get(key)
使用缓存,改进后的代码:
$(function(){ var sheng = $("#sheng"); var shi = $("#shi"); var xian = $("#xian"); shi.change(function(){ var pid = $(this).val(); var xianList = cache().get(pid); if(xianList) { createOptions(xianList, xian); } else { $.get("/ajax/findCity", {pid: pid}).done(function(xianList){ cache().put(pid, xianList); createOptions(xianList, xian); }); } }); sheng.change(function(){ var pid = $(this).val(); var shiList = cache().get(pid); if(shiList) { createOptions(shiList, shi); shi.change(); } else { $.get("/ajax/findCity", {pid: pid}).done(function(shiList){ cache().put(pid, shiList); createOptions(shiList, shi); shi.change(); }); } }); var shengList = cache().get("shengList"); if(shengList) { createOptions(shengList, sheng); sheng.change(); } else { $.get("/ajax/findSheng").done(function(shengList){ cache().put("shengList", shengList); createOptions(shengList, sheng); sheng.change(); }); } }); |
注意改动后,事件定义的顺序。因为在本地加载数据非常快,因此要预先定义好事件,再触发事件。如果顺序颠倒,会出现事件触发,但事件函数没有被调用的现象。
参考进度 (1.5课时)
第2讲 分页实例
课程内容
第二章分页页面部分使用jQuery改写如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <script type="text/javascript" src="/ajax/js/jquery-1.11.1.js"></script> <script type="text/javascript"> $(function(){ var pagesizeSelect = $("#pagesize").change(function() { loadpage(1); }); function createTbody(map) { var tbody = $("#tbody").empty(); for(var i = 0;i < map.list.length;i++){ var tr = $("<tr>"); var td0 = $("<td>"+(i+1)+"</td>"); var td1 = $("<td>"+(map.list[i].id)+"</td>"); var td2 = $("<td>"+(map.list[i].name)+"</td>"); tr.append(td0).append(td1).append(td2).appendTo(tbody); } } function createA(index, text) { var a = $("<a href='javascript:void(0)'>"+text+"</a>"); a.click(function() { loadpage(index); }); return a; } function createSpan(text) { return $("<span>"+text+"</span>"); } function createPager(map, index) { var pager = $("#pager").empty(); var first = (index>1)?createA(1, "首页"):createSpan("首页"); var prev = (index>1)?createA(index-1, "上一页"):createSpan("上一页"); var next = (index<map.total)?createA(index+1, "下一页"):createSpan("下一页"); var last = (index<map.total)?createA(map.total, "终页"):createSpan("终页"); pager.append(first).append(createSpan(" ")).append(prev).append(createSpan(" ")); // 计算页号的范围,参考了百度的实现 var begin, end; if(map.total <= 10) { begin = 1; end = map.total; } else { if(index <= 6) { begin = 1; end = 10; } else { if(map.total - index <= 4) { begin = map.total - 9; end = map.total; } else { begin = index - 5; end = index + 4; } } } for(var i = begin ; i <= end; i++) { var page = (i == index)?createSpan(i):createA(i, i); pager.append(page).append(createSpan(" ")); } pager.append(next).append(createSpan(" ")).append(last); } function loadpage(index) { $.get("/ajax/findCityPage", {index:index,pagesize:pagesizeSelect.val()}, function(map){ createTbody(map); createPager(map, index); }); } loadpage(1); }); </script> </head> <body> <!-- 实现局部刷新(ajax)的分页 --> <table width="100%" border="1"> <thead> <tr> <th>序号</th> <th>id</th> <th>name</th> </tr> </thead> <tbody id="tbody"></tbody> </table> <div id="pager"></div> <select id="pagesize"> <option value="10" selected>每页10条</option> <option value="20">每页20条</option> <option value="50">每页50条</option> <option value="100">每页100条</option> </select> </body> </html> |
参考进度 (0.5课时)
第3讲 树结构实例
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <style type="text/css"> #tree ul{display:none;} </style> <script type="text/javascript" src="/ajax/js/jquery-1.11.1.js"></script> <script type="text/javascript"> $(function(){ function createUL(json, parent){ var ul = $("<ul>").appendTo(parent); for(var i = 0;i < json.length;i++) { var li = $("<li id='"+json[i].id+"'><span>"+json[i].name+"</span></li>"); li.appendTo(ul); } ul.show(500); } $("#tree").on("click", "li", function(e){ e.stopPropagation(); var me = this; // 将this重命名,以便内嵌的函数引用 var ul = $(me).children("ul"); if(ul.size()==0) { // 是否有ul子元素 $.post("/ajax/findCity", {pid: this.id}, function(json){ createUL(json, me); }); } else { //已经查询过了 ul.toggle(500); // 只切换显示状态 } }); $.post('/ajax/findSheng',function(json){ createUL(json, "#tree"); }); }); </script> </head> <body> <div id="tree"></div> <hr/> <ul> <li id="110000"><span>北京</span> <ul></ul> </li> <li id="120000"><span>天津</span></li> <li id="130000"><span>河北</span></li> </ul> </body> </html> |
参考进度 (1课时)
第4讲 AutoComplete实例
课程内容
Dao层代码
public List<String> findByTerm(String term) { Connection conn = null; PreparedStatement psmt = null; ResultSet rs = null; try { String sql = "select name from cities where name like ? or pinyin like ?"; conn = JdbcUtil.getConnection(); psmt = conn.prepareStatement(sql); psmt.setString(1, term + "%"); psmt.setString(2, term + "%"); rs = psmt.executeQuery(); List<String> list = new ArrayList<String>(); while(rs.next()) { list.add(rs.getString("name")); } return list; } catch(Exception e) { throw new RuntimeException(e); } finally { JdbcUtil.close(rs, psmt, null); } } |
页面代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <style type="text/css"> ul.result {position: absolute; list-style: none; padding: 0; margin: 0; display: none; font-size: 11px;border:1px black solid} ul.result li{margin: 2px;} .over{color:white;background: blue;} </style> <script type="text/javascript" src="/ajax/js/jquery-1.11.1.js"></script> <script type="text/javascript"> $(function(){ var h; var index = -1; $("#a1").keyup(function(e){ console.log(e.keyCode); if(e.keyCode == 13) { // 处理回车事件 if(index > -1) { var li = $("#"+this.id+"_result li:eq("+index+")"); li.trigger("click"); } } else if(e.keyCode == 27) { // 处理Esc事件 var ul = $("#"+this.id+"_result"); index = -1; ul.hide(); } else if(e.keyCode == 38) { // 处理上箭头事件 var lis = $("#"+this.id+"_result li"); if(index > 0) index--; lis.removeClass("over").eq(index).addClass("over"); } else if(e.keyCode == 40) { // 处理下箭头事件 var lis = $("#"+this.id+"_result li"); if(index < lis.size() - 1) index++; lis.removeClass("over").eq(index).addClass("over"); } else if((e.keyCode > 48 && e.keyCode <=127) || e.keyCode==8 || e.keyCode==46) { // 可打印字符,和退格,删除字符 var me = this; var pos = $(me).position(); var left = pos.left + 1; var top = pos.top + $(me).outerHeight() + 5; var width = $(me).outerWidth(); if(h) clearTimeout(h); // 取消上次请求 var term = $.trim(this.value); console.log(term); var ul = $("#" + me.id + "_result").empty().hide(); if(term.length < 1 ) { // 小于一个字符,不发请求 return false; } h = setTimeout(function(){ // 500毫秒后再发请求,这样可以让请求有机会取消 $.get("/ajax/autocomplete", {term: term}, function(list){ if(list.length > 0) { if(ul.size()==0) { ul = $("<ul class='result' id='"+me.id+"_result'>"); ul.appendTo("body"); } for(var i = 0; i < list.length; i++) { ul.append("<li>"+list[i]+"</li>") } ul.width(width).css({left:left, top:top}).show(); } }); }, 500); } else { return false; } }); $("body").on("mouseover", ".result li", function(){ var me = this; $(this).parent().children().each(function(i, li){ if(li == me) { $(li).addClass("over"); index = i; }else { $(li).removeClass("over"); } }); }) .on("mouseout", ".result li", function(){ $(this).removeClass("over"); index = -1; }) .on("click", ".result li", function(){ var ul = $(this).parent(); var id = ul.attr("id").replace("_result", ""); $("#"+id).val(this.innerHTML); ul.hide(); }); }); </script> </head> <body> <input type="text" id="a1"/> </body> </html> |
参考进度 (2课时)
第五章Ajax与jQuery提高
注意:本章内容涉及文件上传,最好能调整一下课程顺序,放在Struts之后讲,能够简化处理文件上传流程
第1讲 将分页代码做成jQuery插件
课程内容
编写如下js插件文件
$.fn.extend({ "grid": function(options, extraParams){ // 默认选项 var defaultOptions = { index: 1, pagesize: 10, pagemax: 10, pageleft: 5 }; // 执行其它方法 if(typeof options === "string") { if(options === "search") { this.each(function(i, table){ var opts = $(table).data("options"); $.extend(opts, extraParams); loadpage.call($(table)); }); } // 执行构造方法 } else if(typeof options === "object") { // 考虑了jQuery对象选中多个元素的情况 this.each(function(i, table){ // 覆盖默认选项 var opts = $.extend(defaultOptions, options); // 为每个table存储它的选项 var t = $(table).data("options", opts); // 生成表格内容, 用call 来保证函数内部的this是当前表格对应的jQuery对象 createTable.call(t); // 首次加载 loadpage.call(t); }); } // 创建页号超链接,其中title记录了当前页码 function createA(index, text) { return $("<a href='javascript:void(0)' title='"+index+"'>"+text+"</a>"); } // 创建span文本 function createSpan(text) { return $("<span>"+text+"</span>"); } // 查询 function loadpage() { var opts = this.data("options"); var grid = this; $.get(opts.url, {index:opts.index,pagesize:opts.pagesize}, function(map){ refreshTbody.call(grid, map); refreshPager.call(grid, map, opts.index); }); } // 生成表格内容 function createTable() { var me = this; var opts = me.data("options"); var thead = $("<thead>"); var theadTr = $("<tr>").appendTo(thead); // 生成表格头 for( var i = 0; i < opts.columns.length; i++) { $("<th>"+opts.columns[i].text+"</th>").appendTo(theadTr); } // 生成表格体 var tbody = $("<tbody>"); me.append(thead).append(tbody); // 生成页码div var pager = $("<div class='pager'>").insertAfter(me); pager.on("click", "a", function(){ $.extend(opts, {index: parseInt(this.title)}); loadpage.call(me); }); } // 更新表格体内容 function refreshTbody(map) { var opts = this.data("options"); var tbody = this.find("tbody").empty(); for(var i = 0;i < map.list.length;i++){ var tr = $("<tr>").appendTo(tbody); for(var j = 0; j < opts.columns.length; j++) { var pname = opts.columns[j].index; // 该列的属性名 var pvalue = map.list[i][pname]; // 取得该列的值 var value = (pvalue===undefined)?"":pvalue; if(opts.columns[j].renderObject) { var obj = opts.columns[j].renderObject(value, i); $("<td>").append(obj).appendTo(tr); continue; } if(opts.columns[j].renderer) { value = opts.columns[j].renderer(value, i); } $("<td>"+(value)+"</td>").appendTo(tr); } } } // 更新页码 function refreshPager(map, index) { var opts = this.data("options"); var pager = this.next(".pager").empty(); var first = (index>1)?createA(1, "首页"):createSpan("首页"); var prev = (index>1)?createA(index-1, "上一页"):createSpan("上一页"); var next = (index<map.total)?createA(index+1, "下一页"):createSpan("下一页"); var last = (index<map.total)?createA(map.total, "终页"):createSpan("终页"); pager .append(first) .append(createSpan(" ")) .append(prev) .append(createSpan(" ")); // 计算页号的范围,参考了百度的实现 var be = calculateBeginEnd(index, map.total, opts.pageleft, opts.pagemax); for(var i = be.begin ; i <= be.end; i++) { var page = (i == index)?createSpan(i):createA(i, i); pager.append(page).append(createSpan(" ")); } pager.append(next).append(createSpan(" ")).append(last); } /* index: 当前页页码 total: 总页码 left: 当前页位于*时左侧的页码数 max: 最大页数 */ function calculateBeginEnd(index, total, left, max) { var begin, end; var right; // 当前页位于*时右侧的页码数 right = max - left -1; if(total <= max) { begin = 1; end = total; } else { if(index <= left+1) { begin = 1; end = max; } else { if(total - index <= right) { begin = total - (max-1); end = total; } else { begin = index - left; end = index + right; } } } return {begin:begin, end:end} } return this; // 链式调用 } }); |
要点:
u 如何利用$.extend()拷贝对象属性
u 链式调用的好处,以及带来的问题:需要在同一个扩展方法里区分构造方法和其它方法
u 利用.data()来将选项对象绑定到jQuery对象
u 利用call方法来改变function的执行上下文(this上下文)
u 如何将变化的内容抽取为选项对象,以达到通用的目的
u 对表格每一列的抽象
表格插件源码写好后,可以使用yui-compressor压缩以减少js文件体积,最后在页面上引用js插件就变得简单:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <script type="text/javascript" src="/ajax/js/jquery-1.11.1.js"></script> <script type="text/javascript" src="grid-min.js"></script> <script type="text/javascript"> $(function(){ $("#g1").grid({ url: "/ajax/findCityPage", columns:[ {text: "序号", renderer: function(value, i){ return i+1; }}, {index:"id", text:"编号"}, {index:"name", text:"名称"}, {index:"id", text:"删除", renderObject: function(value){ return $("<input type='button' value='删除'>").click(function(){ alert(value); }); }} ] }); $("#g2").grid({ url: "/ajax/findCityPage", pagesize:5, pagemax:5, pageleft:2, columns:[ {index:"id", text:"编号"}, {index:"name", text:"名称"} ] }); $("#pagesize").change(function(){ $(".grid").grid("search", {index: 1, pagesize: parseInt(this.value)}); }); }); </script> </head> <body> <!-- 实现局部刷新(ajax)的分页 --> <table width="100%" border="1" class="grid" id="g1"></table> <!-- 实现局部刷新(ajax)的分页 --> <table width="100%" border="1" class="grid" id="g2"></table> <select id="pagesize"> <option value="10" selected>每页10条</option> <option value="20">每页20条</option> <option value="50">每页50条</option> <option value="100">每页100条</option> </select> </body> </html> |