JavaScript简介
JS可以为HTML页面添加动态效果,这种动态效果是通过规定好的事件触发的。这种动态的效果提高了网页的交互性。同时,AJAX技术使得页面可以异步加载,提高了页面的使用效率(这个后面会说)。
总之,JS在整个前端中来说,是相对重要且和后端交互最多的一个部分。一定要牢牢掌握。
和CSS一样,既然想为网页添加动态效果,其实本质上就是控制网页中的对应的标签所以,JS中也会有各种选择器。选择器用来选定某个标签,不同选择器的效率不同,我们需要按照开发的需求使用对应的选择器。所以你需要知道如何在H5页面中选中对应的标签——通过id、标签名和class,这一部分之前已经讨论过。
1. JS基础
JS是一门编程语言,其代码的编写符合编程语言的规范,包括变量的声明、函数的编写和调用,控制语句(循环和分支)等。要注意的是:JS是弱类型语言,即在变量的声明时,不需要指定变量的类型,除此之外,其编写风格和Java基本类似。
在编写JS代码的时候一定要学会灵活的使用IDE的代码提示功能!!
1.1 JS中的事件(Event)
概念
开头提到了事件这一个概念,我的理解**就是JS规定的一些用户可做出的动作。最常见的我们单击某个按钮(input标签的bottom),这在JS看来就是一个事件。JS会捕捉当前页面上所发生的事件,并通过函数(function)**来造成某些效果。可以说JS就是一个事件驱动型的语言。
如果你有通过编程语言操作文件的经历,你肯定知道,第一步就是获取文件的句柄,即在你的程序中,声明一个变量,这个变量在整个程序执行的过程中代表的就是这个文件,所以对这个变量的操作就等同于对文件的操作。同样的,在JS中也有类似的概念,**每个事件对应一个句柄,**通过在标签中声明某个句柄就可以获取这个事件,接着,浏览器就会监听当前页面,如果对应标签上发生了事件,那么就会获取到这个事件的句柄,然后去执行对应的代码。其过程如下:(图片来自这里)
常见的JS事件
事件 | 名称 | 句柄 |
---|---|---|
单击 | click | onclick |
双击 | dbclick | ondbclick |
获得焦点 | focus | onfocus |
失去焦点 | blur | onblur |
通过句柄=“函数”
的方式来为某个标签绑定上函数。例如<input type="button" value="click here" onclick="window.alert(123)"/>
.
内置对象
JS中我们常常需要用到一些内置对象,这些内置对象是浏览器生成的,直接提供给用户,方便我们操作。其关系如下:(图片源点击这)
常用的内置对象:
- window:JS中,window指代当前浏览器的窗口。
window.fucntion(parameters)
window可以省略。 - document:整个HTML页面,通过document可以获取当前页面的标签对象。
- console:提供和控制台相关的方法,主要是方便我们调试和检查代码。
1.2 JS嵌入方式
和CSS一样,在web开发中,JS也是为了增强HTML页面的能力的,所以如果想使用JS,就必须在HTML中嵌入JS代码,一般有三种方式:(和CSS基本一致)
- 在标签的属性域绑定事件,并执行函数:
<input type="button" value="click here" onclick="window.alert(123)"/>
; - 在HTML页面中编写JS代码块;
<script type="text/javascript"> 你的JS code </script>
; - 引入独立的JS文件:
<script scr="你的JS文件路径" type="text/javascript" charset="UTF-8"></script>
。
- 示例: 代码块内部的代码会在页面一打开就执行,且可以写在任何位置
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>单击事件</title>
<script src="my.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<input type="button" value="click here" onclick="window.alert('hello world')"/>
<script type="text/javascript">
alert(hello);
alert(hello world);
</script>
</body>
</html>
1.3 定义变量
在script标签体中定义:
如果该变量没有赋值,那么就会赋值为undefined。
<script type="text/javascript">
var age = 10;
console.log(age);
</script>
1.4 JS的函数
直接写在JS代码块的内容会被执行,不论是否由事件引发。所以,我们需要将由一些特定事件而引发的动作封装到函数中,再将函数与事件绑定。
Code
function hello() {
window.alert(1234)
window.alert('欢迎来到本站')
}
function add(a,b) {
c = a + b;
alert(c);
}
// 另一种函数声明方式
sayhello = function() {
函数体
}
window.alert("这句话将会被直接调用");
var a = 10;
var b = 20;
var c = 0;
有了函数,我们必须将其与对应的事件绑定才可以发挥作用,总的来说,JS事件绑定有两种方式:
- 嵌入式绑定:
<input type="botton" onclick="func()"/>
- 基于DOM对象的绑定:通过选择器获取到一个DOM对象 dom1,用类似于声明的方式赋值:
dom1.onclick=func1;
1.5 JS选择器
和CSS一样,JS中也有选择标签的操作。之前说到的,每个标签都会被浏览器解析成唯一的对象,同时浏览器为我们提供了一个document对象,这个对象代表了当前的THML页面,所以我们可以通过这个对象来获取当前的页面的标签。通过getElementByXXX()或者getElementsByXXX()
的方式获取对象,在函数内部拿到了一个标签对象,那么我们就可以在JS函数里面对这个对象进行任何操作,包括修改标签的属性,为标签写入文本和HTML代码等。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>获取HTML标签对象</title>
</head>
<body>
<script type="text/javascript">
function div1() {
var div1 = document.getElementById("div1");
console.log(div1);
}
function botton1() {
// 获取标签
var click = document.getElementById("botton1");
console.log(click);
}
function text1() {
var text1 = document.getElementById("text1")
console.log(text1);
}
</script>
<div id="div1" onmousedown="div1()">
我是一个DIV
</div>
<input type="text" id="text1" value="" onfocus="text1()" />
<input type="button" name="botton1" id="botton1" value="click" onclick="botton1()" />
</body>
</html>
执行效果:
1.6 JS获取的标签对象
通过get方法可以获取标签对象,这个对象提供了很多属性和方法,我们可以修改对应的属性和方法来达到对标签的控制。我们可以通过IDE 的代码提示来寻找需要的函数和属性,有两个常用的属性:
- innerText:一个标签中修饰的文字部分,通过这个属性我们可以获取一个标签体的内容(返回的是string),也可以修改它。
- innerHTML:和innerText基本上差不多,对这个属性进行修改时,修改的内容会被解析成HTML代码。
一个案例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>innerText和innerHTML</title>
<script>
function show() {
var div1 = document.getElementById("div1");
console.log("通过innerText获取的div1的内容是"+div1.innerText);
console.log("通过innerHTML获取的div1的内容是"+div1.innerHTML);
}
function change() {
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
div2.innerHTML = "<font color='blue'>我是通过innerHTML改变的,我是蓝色的</font>";
div3.innerText = "我是通过innerText改变的,我是白色";
}
</script>
</head>
<body>
<div id="div1">
我是一个div!
</div>
<input type="button" name="" id="" value="测试获取内容" onclick="show()" />
<input type="button" name="" id="" value="测试修改内容" onclick="change()" />
<div id="div2">
我是一个div!
</div>
<div id="div3">
我是一个div!
</div>
</body>
</html>
显示效果:
2. jQuery
JQuery可以理解为是JS的一种框架,基于JS,JQuery封装了JS对DOM对象的操作,使其简化且高效。
学习JQuery主要有两点:
- JQuery的选择器和过滤器;
- JQuery提供的常用功能函数。
2.1 如何导入JQuery
首先我们需要导入JQuery的源码:
<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
这时候你就可以在你的HTML页面中编写JQuery代码了,当然你也可以导入独立的JQuery文件:
<script type="text/javascript" src="你的jquery文件位置"></script>
2.2 对象
JQ对象绝对不是新的概念,他只是将DOM对象(JS操作的对象)封装起来使用,可以理解为JQ为我们开辟了数组,存储了我们要操作的DOM对象。
DOM对象
- 在HTML页面被加载时, 浏览器会创建出一个DOM树, 每个节点就是一个标签
- 一个DOM对象对应一个标签
- 我们通常对标签的操作本质上是调用DOM对象的某些方法,或者修改其属性
- 这就是为什么可以使用
this
关键字,因为本质上每个标签都是一个对象,this
指向的就是当前标签这个对象
JQ对象
- 由JQuery函数创建
$()
- 本质上是一个数组
- 存放着定位到的DOM对象
- 通过函数来操作这些对象
- Jquery对象的操作和数组完全一致, 支持
[]
操作,具有length属性, 实际上, 生成Jquery对象就是将DOM对象放入数组的过程.
2.3 JQ选择器
选择器和CSS中的作用一样,是为了选择指定的标签,同时,过滤器从作用上也可以理解为是一种选择器,是通过过滤条件来选中标签对象。
基本选择器:
$("#id编号")
:相当于document.getElementById(“id”); 只选中一个元素,但是返回的是一个数组。$(".class")
:相当于document.getElementByClassName(“class名称”); 根据类名来定位$("标签名"
) :相当于document.getElementsByTagName(“标签名”); 根据标签名来定位- 支持按照正则表达式选择
- 组合选择器:
$("条件1, 条件2")
: 会获得多个标签
除了基本选择器以外,其他选择器只在特定的场景比较好用。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JQ复习</title>
<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
function changeByJinghao() {
var div1 = $("#div1");
div1[0].innerHTML = "<font>我通过单击change1按钮发生改变</font>";
}
function changeByDian() {
var eles = $(".div2");
eles[0].innerHTML = "<font>我通过单击change2按钮发生改变</font>";
eles[1].innerHTML = "<font>我通过单击change2按钮发生改变</font>";
}
function changeByLabelName() {
var eles = $("span");
eles[0].innerHTML = "<font>我通过单击change3按钮发生改变</font>";
eles[1].innerHTML = "<font>我通过单击change3按钮发生改变</font>";
}
function changeByMulit() {
var eles = $("#span1, #div3");
eles[0].innerHTML = "<font>我通过单击change4按钮发生改变</font>";
eles[1].innerHTML = "<font>我通过单击change4按钮发生改变</font>";
}
</script>
</head>
<body>
<div id="div1">我是div1</div>
<input type="button" name="" id="" value="change1" onclick="changeByJinghao()"/>
<div class="div2">我是div2</div>
<div class="div2">我是div2</div>
<input type="button" name="" id="" value="change2" onclick="changeByDian()"/><br>
<span>我是一个span</span><br>
<span>我也是一个span</span><br>
<input type="button" name="" id="" value="change3" onclick="changeByLabelName()"/>
<div id="div3">我是div3</div>
<span id="span1">我是span1</span><br>
<input type="button" name="" id="" value="change4" onclick="changeByMulit()" />
</body>
</html>
层级选择器
我们之前说过的,HTML页面会被解析成一棵DOM树,而树的最大特征就是有层级的关系,父子关系和兄弟关系。当需求要选中DOM树中某一层的节点,或者基于某个节点去寻找他的父或者子节点时,使用层级选择器的效率会很高。
可以根据标签之间的层级关系(父子,兄弟)来定位,因为HTML本质上是一颗dom树.
例如:
<tr>
<td>
<font id="f1"></font>
<font id="f2"></font>
</td>
</tr>
标签关系:
1. 直接子标签: td是tr的子标签
2. 间接子标签: font 是tr的间接子标签(孙子关系)
3. 兄弟标签: 平行关系
哥哥标签:f1是f2的哥哥
使用方法:
$("定位父标签条件>定位子标签条件")
:选择当前父标签下的所有满足条件的直接子标签。$("定位父标签条件 定位子标签条件")
:选择当前父标签下的所有满足条件的直接子标签,和间接子标签。$("定位当前签条件~定位兄弟签条件")
:定位当前标签之后的满足条件的兄弟标签。$("定位当前签条件+定位兄弟签条件")
:定位当前标签之后紧邻的的满足条件的兄弟标签。$("定位当前标签条件").siblings("定位兄弟标签条件")
:定位当前标签所有满足条件的兄弟标签。$('#d1').next()
:定位当前标签的后面一个兄弟标签。$('#d1').nextAll()
:定位当前标签的后面所有兄弟标签。$('#d1').prev()
:定位当前标签的前面一个兄弟标签。$('#d1').prevAll()
:定位当前标签的前面所有兄弟标签。$('#d1').parent()
:定位当前标签的直接父标签。
注意:以上所有的函数参数都可以传入基本选择器进行进一步筛选。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JQ--层级选择器</title>
<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
function test1() {
var elements = $("#fa1>font");
var elements1 = $("#fa1>#fontt1");
console.log(elements1[0]);
for (var i = 0; i < elements.length; i++) {
console.log("element"+i+"-----"+elements[i]);
elements[i].color = "green";
}
}
function test2() {
var elements = $("#fa2 font");
for (var i = 0; i < elements.length; i++) {
console.log("element"+i+"-----"+elements[i]);
elements[i].color = "green";
}
}
function test3() {
var elements = $("#fa3~div");
for (var i = 0; i < elements.length; i++) {
elements[i].style = "background-color:red";
}
}
function test4() {
var elements = $("h3+div");
for (var i = 0; i < elements.length; i++) {
elements[i].style = "background-color:green";
}
}
function test5() {
var elements = $("#fa3").siblings("div");
for (var i = 0; i < elements.length; i++) {
console.log(elements[i]);
}
}
</script>
</head>
<body>
<!-- $("定位父标签条件>定位子标签条件")-->
<div id="fa1">
<font color="red" id="bro1">我是fa1————bro1</font><br>
<font id="bro2">我是fa1————bro2</font>
<div id="bro3"><font size="" color="red" id="fontt1">能定位到我吗</font></div><br>
<input type="button" name="" id="" value="测试第一种方法" onclick="test1()" />
</div>
<!-- $("定位父标签条件 定位子标签条件") -->
<div id="fa2">
<font color="red" id="bro1">我是fa1————bro1</font><br>
<font id="bro2">我是fa1————bro2</font>
<div id="bro3"><font size="" color="red" id="fontt1">能定位到我吗</font></div><br>
</div>
<input type="button" name="" id="" value="测试第一种方法" onclick="test2()" />
<h3>下面是兄弟标签的测试</h3>
<div id="fa3">我是fa3标签</div>
<div id="fa4">我是fa4标签</div>
<div class="c1">我是fa5标签</div>
<div class="c1">我是fa6标签</div>
<!-- <div id="" style="border: 33px; bgcolor: antiquewhite;">
234343
</div> -->
<!-- $("定位当前签条件~定位兄弟签条件") -->
<input type="button" name="" id="" value="测试第三种方法" onclick="test3()" />
<!-- $("定位当前签条件+定位兄弟签条件") -->
<input type="button" name="" id="" value="测试第四种方法" onclick="test4()" />
<!-- $("定位当前标签条件").siblings("定位兄弟标签条件") -->
<input type="button" name="" id="" value="测试第五种方法" onclick="test5()" />
</body>
</html>
显示效果:
input标签选择器
input标签作为接受用户输入的标签,在HTML的编写中起着重要的作用,JQ提供了对input标签的选择方法:$(":input标签的type属性")
。例如:$(":button")
,选中当前页面中所有的按钮。
2.4 JQuery的过滤器
对已经放入JQ对象的标签进行二次的过滤。
基本过滤器:时刻记住JQ对象是一个数组
$("selector: first")
: 在选出的JQ对象中,留下第一个DOM对象$("selector: last")
: 在选出的JQ对象中,留下最后一个DOM对象$("selector: eq()")
: 在选出的JQ对象中,留下指定下标的DOM对象$("selector: lt()")
: 在选出的JQ对象中,留下小于指定下标的DOM对象$("selector: gt()")
:在选出的JQ对象中,留下大于指定下标的DOM对象
属性过滤器:按照标签的属性来进行过滤
$("selector[attributions]")
: 在选出的JQ对象中,留下指定属性赋值的DOM对象(如果没有手动为属性赋值,那么默认是空值)。$("selector[attributions = 'value']")
: 在选出的JQ对象中,留下指定属性赋指定值(value)的DOM对象。$("selector[attributions ^= 'value']")
: 在选出的JQ对象中,留下指定属性的值以value开头的DOM对象。$("selector[attributions $= 'value']")
:在选出的JQ对象中,留下指定属性的值以value结尾的DOM对象。$("selector[attributions *= 'value']")
: 在选出的JQ对象中,留下指定属性的值包含value的DOM对象。
以上各种过滤方法都可以组合使用。
工作状态属性过滤器:本质上还是一个属性过滤器
html标签属性分类:
- 基本属性:绝大多数标签都拥有的属性———(id,name ,title,rowspan)
- 样式属性:背景,字体,边框
- value属性:只存在表单域标签中(input,select,textarea)
- 工作状态属性:只存在表单域标签[chekced,disabled,selected]
- 监听事件属性:onclick ,onchange,onfocus, onbulr
基于工作状态属性,工作状态属性过滤器有: $("selector:enabled")
:在选出的JQ对象中,留下状态为enabled的DOM对象。$("selector:disabled")
:在选出的JQ对象中,留下状态为disabled的DOM对象。$("selector:selected")
:在选出的JQ对象中,留下状态为selected的DOM对象。$("selector:chekced")
:在选出的JQ对象中,留下状态为chekced的DOM对象。
2.5 JQuery常用函数
函数名 | 功能 | 案例 |
---|---|---|
val() | 返回jq对象第一个元素的值 | $myobj.val() |
val(“参数”) | 为JQuery对象中存储的所有DOM对象进行赋值 | |
each(函数名) | 将传入的函数循环调用,每次读取一个下标值和下标对应的元素值 | each(myfunc) myfunc(index, element) |
show(毫秒值) | 让Jquery元素在一定时间内显示出来 | ${“div”}.show(300) |
hide(毫秒值) | 让Jquery元素在一定时间内消失 | ${“div”}.hide(300) |
remove() | 删除当前标签的子标签 | ${“div”}.empty() |
remove() | 删除当前标签和子标签 | ${“div”}.remove() |
append(子标签) | 父标签调用, 给自己添加一个子标签 | ${“#father”}.append(“son”) |
appendTo() | 子标签调用, 给自己添加一个父标签 | ${“son”}.appendTo(“father”) |
2.6 JQuery的函数绑定
除了使用JS提供的函数绑定方式,JQ也提供了一些绑定方式,且更加灵活。
注意:绑定事件的操作要么发生在中,要么就在HTML页面加载手动触发,即使用$(function() {绑定操作})
,这样的方式来使得绑定生效。
通过监听事件绑定:
JQuery中重命名了事件,其规律是,把JS中的事件名称前的“on”去掉。
JS监听的事件 | JQ监听的事件 |
---|---|
onclick | $obj.click(func) |
onblur | $obj.bulr(func) |
onfocus | $obj.focus(func) |
onhandover | $obj.handover(func) |
… | … |
通过bind的方式绑定:
通过这种方式绑定可以解除,但是这种方式不可对动态的资源进行绑定,比如后来增加的内容就无法绑定上事件。
语法格式:
JSObject.bind("JQuery事件名",处理函数);
JSObject.unbind(处理函数);
解绑指定函数。JSObject.bind();
解绑全部函数。
通过on的方式绑定:官方推荐
从JQ 1.7之后,官方就推出on()和off()
方法来实现事件的绑定和解绑。使用 on()
方法添加的事件处理程序适用于当前及未来的元素(比如JS在触发了事件后创建的新元素)。
语法格式:
$(selector).on(event,childSelector,data,function)
:绑定事件
参数 | 描述 |
---|---|
event | 必需。规定要从被选元素添加的一个或多个事件或命名空间。由空格分隔多个事件值,也可以是数组。必须是有效的事件。 |
childSelector | 可选。规定只能添加到指定的子元素上的事件处理程序(且不是选择器本身,比如已废弃的 delegate() 方法)。 |
data | 可选。规定传递到函数的额外数据。 |
function | 可选。规定当事件发生时运行的函数 |
$(selector).off(event,selector,function(eventObj),map)
:解绑事件
参数 | 描述 |
---|---|
event | 必需。规定要从被选元素移除的一个或多个事件或命名空间。由空格分隔多个事件值。必须是有效的事件。 |
selector | 可选。规定添加事件处理程序时最初传递给 on() 方法的选择器。 |
function(eventObj) | 可选。规定当事件发生时运行的函数。 |
map | 规定事件映射 ({event:function, event:function, …}),包含要添加到元素的一个或多个事件,以及当事件发生时运行的函数。 |
$(selector).one(event,data,function)
: one() 方法为被选元素添加一个或多个事件处理程序,并规定当事件发生时运行的函数。当使用 one() 方法时,每个元素只能运行一次事件处理程序函数。
参数 | 描述 |
---|---|
event | 必需。规定添加到元素的一个或多个事件。由空格分隔多个事件值。必须是有效的事件。 |
data | 可选。规定传递到函数的额外数据。 |
function | 必需。规定当事件发生时运行的函数。 |
3. AJAX
3.1 基础知识
全局刷新:由页面发起的请求,只能发起一次。
- 必须由浏览器发起页面请求;
- 发起的请求由服务器处理,响应回来的数据会存储在浏览器的内存中,并覆盖原有的内存;
- 所以,我们只能拿到响应的内容,而无法去显示被覆盖的内容。
局部刷新:一个页面有多个异步对象(XMLHttpRequest
),每个对象都可以向服务器发起请求: - 浏览器不发送请求;
- 请求将委托给异步对象发送请求,且服务器响应的内容也会被缓存到异步对象的内存中,并覆盖之前的内容;
- 这使得其他没有被覆盖内容仍然可以正常显示。
如何创建XMLHttpRequest对象呢?
var xmlObj = new XMLHttpRequest();
该对象存在于浏览器的内存中,隶属于某个页面。
3.2 什么是AJAX
异步的JavaScript和XML. AJAX是一种技术方法,而不是编程语言。其核心是JS和XML。
- JS负责创建异步对象,发送请求和更新DOM对象;
- XML是负责在客户端和服务器之间传输数据;现在多使用JSON(轻量,效率高)
什么是异步?
异步的概念来自操作系统:两个线程执行是相互独立, 即没有线程间通信.。
一个浏览器可以创建多个线程(一个页面中), 这些线程有的是同步的(彼此之间有通信, 需要相互等待), 有的异步的.
- 使用AJAX可以在一个页面中发起多个请求, 提升加载速度。
- 使用AJAX可以实现局部刷新, 这样的当我们需要局部修改某些内容时, 就不用将整个页面都修改了( 转发 或者 重定向). 而且即使跳转回原来的页面, 也无法保存之前用户输入的东西, 比如在用户登录时, 用户名信息输入错误无法登录, 这种情况下, 跳转回login页面会把用户之前的东西清空, 这样用户体验差, 而且速度慢, 因为我们不需要全部刷新, 只需要提示用户名或者密码错误就好.
3.3 使用AJAX
本质上就使用上文提到的异步对象。AJAX的使用有相对固定的步骤,熟练掌握这几个步骤就可以很轻松的学习。
属性 | 描述 |
---|---|
onreadystatechange | 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。 |
readyState | 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
0: 请求未初始化
1: 服务器连接已建立 2: 请求已接收 3: 请求处理中 4: 请求已完成,且响应已就绪 |
status |
200: "OK"
404: 未找到页面 |
使用步骤为:
- 创建异步对象:
var xhr = new XMLHttpRequst()
; - 为异步对象绑定事件:
onreadystatechange
。 - 按照不同的响应(readyState)做出不同的处理动作;
xmlhttp.onreadystatechange=function() { // 在 onreadystatechange 事件中,我们规定当服务器响应已做好被处理的准备时所执行的任务。 if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("myDiv").innerHTML=xmlhttp.responseText; } }
readyState
是如何变化的呢?
- 0:初始创建对象
new XMLHttpRequest()
- 1:初始异步请求对象,
xhr.open()
- 2:发送请求:
xhr.send()
- 3:从服务器端获取数据;
- 4:异步对象处理完数据,交给我们使用,我们需要更新页面的内容。
status
指你的当前的网络状态: - 200:请求成功
- 404:页面找不到
- 500:内部代码错误
一个Demo:注意onreadystatechange 绑定的函数是通过回调的方式来调用的。当请求状态发生变化时,会自动调用这个函数。
<script type="text/javascript">
function checkName() {
var xhr;
if (window.XMLHttpRequest) xhr = new XMLHttpRequest();
else // ie5,6版本使用ActiveXObject来发送AJAX请求
xhr = new ActiveXObject("Microsoft.XMLHTTP");
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == 200) {
var text = xhr.responseText;x
document.getElementById("nameTipsMsg").innerHTML = text;
}
}
xhr.open("get","checkNameServlet?name='123'&password='abc'",true);
xhr.send();
}
</script>
以上面的demo为例:AJAX的执行顺序是:
- 首先执行open语句
- 接着使用send将AJAX请求发送给服务器;
- 如果服务器响应了,再回去执行onreadystatechange的绑定函数。
open函数中第三个参数是决定本次请求是否是异步的:
- true:异步处理请求。使用异步对象发起请求时,不用等待数据处理完毕就可以执行下面的代码。
- false:同步处理请求。使用异步对象发起请求时,必须等待数据处理完毕才可以执行下面的代码。
AJAX常用的形式:
上文提到的方式是AJAX原生的使用方式,也是最基础的内容。现在衍生了很多别的形式,在这里笔者指明一种常用的方式。但是从本质上上来说也是和原生方式使用的是差不多的。**而且原生方式方便我们学习和理解。**请仔细阅读各个参数,你会发现和原生方式一模一样。
$.ajax({
type: ["post","get"],
dataType: "html",
url: '/Resources/GetList.ashx',
data: dataurl,
success: function (data) {
}
});
error:function(data) {
}
3.4 AJAX案例:用户注册判断用户名是否重复:
AJAX的编写需要和服务器进行交互,下面是笔者用来练习的一个案例,前提是你需要掌握:maven的使用、Javaweb基础、H5、JDBC
。Maven是一种项目构建工具(会帮你导包和版本控制,建议掌握),如果你不会也不影响你的代码阅读,可以跳过这部分配置。
如果你想复现这些内容,请修改数据库的配置和java代码中相关的包名。
Maven 仓库配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>javaweb-02-servlet</artifactId>
<groupId>com.yr</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>servlet-01</artifactId>
<packaging>war</packaging>
<name>servlet-01 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.9</maven.compiler.source>
<maven.compiler.target>1.9</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
web.xml:
<servlet>
<servlet-name>Hello.do</servlet-name>
<servlet-class>com.yr.servlet.UserNameCheckServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello.do</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>mytest.jsp</welcome-file>
</welcome-file-list>
servlet: 一定要在web.xml中注册servlet,不然将无法向该servlet发送请求。
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserNameCheckServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String reUserName = req.getParameter("username");
PrintWriter out = resp.getWriter();
System.out.println("进入了servlet");
System.out.println(reUserName.toString());
// 当用户名合法且没有重复时
if (reUserName.length() < 14 && reUserName.length() > 4 && !BaseDao.function(reUserName)) {
out.print("<font color='green'>用户名可用</font>");
} else out.print("<font color='red'>用户名不可用</font>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
数据库查询基类:请注意该类中的function并不规范,Javaweb的编写应当遵守MVC的分层思想,这里只是为了测试方便而已。
import java.sql.*;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
public class BaseDao {
public static String driver;
public static String username;
public static String password;
public static String url;
static {
ResourceBundle resourceBundle = PropertyResourceBundle.getBundle("db");
driver = resourceBundle.getString("driver");
username = resourceBundle.getString("username");
password = resourceBundle.getString("password");
url = resourceBundle.getString("url");
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {e.printStackTrace();}
}
public static Connection getConnection() {
Connection connection = null;
try {
connection = DriverManager.getConnection(url,username,password);
} catch (SQLException throwables) {throwables.printStackTrace();}
return connection;
}
public static boolean function(String username) {
Connection connection = BaseDao.getConnection();
String sql = "select id from smbms_user where userCode=?";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
boolean flag = false;
System.out.println("进入了function");
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,username);
resultSet = preparedStatement.executeQuery();
// 如果查到了内容就返回true。注意:返回true说明用户名重复了。
return resultSet.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {throwables.printStackTrace();}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException throwables) {throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {throwables.printStackTrace();}
}
}
return false;
}
}
JSP页面:
<%--
Created by IntelliJ IDEA.
User: 13918
Date: 2020/9/27
Time: 15:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户注册</title>
<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
//为输入框绑定失去焦点事件
$(function() {
$("#username").on( "blur", checkName);
});
//编写AJAX
checkName = function () {
var obj = document.getElementById("username");
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == "200") {
document.getElementById("nameTipsMsg").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("get", "hello?username="+obj.value,true);
xmlhttp.send();
}
</script>
</head>
<body>
<center>
<h3>User Register</h3>
<form action="/s1/hello" method="get">
<div align="center" id="userRegister">
<div align="center">
<center><div id="nameTipsMsg"></div></center><br>
<label>username:</label>
<input type="text" name="username" id="username" value="" placeholder="请输入用户名"/>
</div>
<br>
<div align="left">
<label>password:</label>
<input type="text" name="password" id="password" value="" placeholder="请输入密码"/>
</div><br>
<input type="submit" value="提交" />
</div>
</form>
</center>
</body>
</html>
显示效果:
4. JSON
JSON现在是最常用的数据交换格式。是以Key-Value的形式存储的。JSON主要包括:
- JSON对象:
{name:"李四"}
- JSON数组:
[{name:"李四", age:12}, {name:"王五",age:123},{name:"赵柳",age:1323}]
&esmp;&esmp;为什么要用JSON呢? - 阅读直观;
- 在Java和JS中读写JSON格式很方便,且JSON文件比较小,传输快。
&esmp;&esmp;处理JSON的工具库:gson,fastjson,jackson。
4.1 使用JSON
导入对应的JSON工具包:
package com.yr.servlet;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
class Person {
String name;
int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
public class testJson {
public static void main(String[] args) throws JsonProcessingException {
Person person = new Person();
ObjectMapper om = new ObjectMapper();
// 将java对象转化成JSON对象
String s = om.writeValueAsString(person);
System.out.println("json---->"+s);
}
}
结果:
在JS中可以使用eval()
将servlet返回的JSON字符串转化成JSON对象,JSON对象的名就是JSON对象的Key。
如果你使用的是JQuery,那么可以使用:var obj = jQuery.parseJSON(ret);
方式来处理JSON文件。
4.2 案例:
下面是一个小的DEMO:利用AJAX搜索用户信息。
页面信息:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSON练习</title>
<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
<script type="text/css">
#showInfo {
float: left;
}
</script>
<script type="text/javascript">
findInfo = function () {
var xmlthttp = new XMLHttpRequest();
var idObj = document.getElementById("userId");
var tips = document.getElementById("Tips");
var elements = $("#name,#password");
if (idObj.value == "") {
tips.innerHTML = showText("输入不可以为空","5","red");
for (var i = 0; i < elements.length; i++) elements[i].setAttribute("value","");
return;
}
xmlthttp.onreadystatechange = function () {
if (xmlthttp.readyState == 4 && xmlthttp.status == 200) {
var ret = xmlthttp.responseText;
var obj = jQuery.parseJSON(ret);
if (obj == null) {
tips.innerHTML = showText("您查找的信息不存在","5","red");
for (var i = 0; i < elements.length; i++) elements[i].setAttribute("value","");
return;
}
tips.innerHTML = showText("您查找的信息如下:","3","green");
elements[0].setAttribute("value", obj.name);
elements[1].setAttribute("value", obj.password);
}
}
xmlthttp.open("get", "JSONTest?id="+idObj.value,true);
xmlthttp.send();
}
showText=function (info, size, color) {
return "<font size='"+size+"' color='"+color+"'>"+info+"</font>";
}
</script>
</head>
<body>
<div>
<input type="text" name="id" id="userId"/>
<input type="button" id="find" value="search" onclick="findInfo()"/>
</div>
<div id="showInfo">
<div id="Tips"></div>
用户名:<input class="info" id="name" /><br>
密码: <input class="info" id="password" />
</div>
</body>
</html>
<servlet>
<servlet-name>JSONTest</servlet-name>
<servlet-class>com.yr.servlet.JSONTestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JSONTest</servlet-name>
<url-pattern>/JSONTest</url-pattern>
</servlet-mapping>
Servlet内容:
package com.yr.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static java.lang.Class.forName;
public class JSONTestServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/json; charset=utf-8");
User user = BaseDao.function1(req.getParameter("id"));
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(user);
resp.getWriter().print(s);
}
}
BaseDao:查找数据库的内容。
package com.yr.servlet;
import java.sql.*;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
/**
*
*/
public class BaseDao {
public static String driver;
public static String username;
public static String password;
public static String url;
static {
ResourceBundle resourceBundle = PropertyResourceBundle.getBundle("db");
driver = resourceBundle.getString("driver");
username = resourceBundle.getString("username");
password = resourceBundle.getString("password");
url = resourceBundle.getString("url");
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection connection = null;
try {
connection = DriverManager.getConnection(url,username,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
public static User function1(String id) {
Connection connection = BaseDao.getConnection();
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = "select userName, userPassword from smbms_user where id=?";
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,id);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
return new User(resultSet);
}
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
closeResource(connection,preparedStatement,resultSet);
}
return null;
}
public static boolean closeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
boolean flag = true;
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
flag = false;
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
flag = false;
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
flag = false;
}
}
return flag;
}
}
User类:
package com.yr.servlet;
import java.sql.ResultSet;
import java.sql.SQLException;
public class User {
String name;
String password;
public User() {}
public User(ResultSet resultSet) {
try {
setName(resultSet.getString("userName"));
setPassword(resultSet.getString("userPassword"));
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
}
效果展示: