八、DOM 编程
1.DOM(Document Object Model),文档对象模型:
将 HTM L文档进行模型化处理,形成一颗结构化的文档树,从而提供访问,修改文档的统一编程接口(API),一旦掌握 DOM 编程,就可以使用 JavaScript 操作整个 HTM L文档。(将 HTML 元素(HTML标签)抽象成一个一个的 DOM 对象,然后通过 JavaScript 来访问)
2.HTML 文档可以抽象成一颗 DOM 树,如下图:

HTML 文档通过浏览器解释执行之后形成了一颗 DOM 树,树上的每一个元素都是 DOM 对象,称为一个节点,然后节点又分为普通元素节点,属性节点,文本节点等等。
3.补充知识:BOM 对象(Browser Object Model),浏览器对象模型
(1)window 对象:
代表整个浏览器对象,是一个全局的对象,我们在 JavaScript 中声明的全局变量和全局函数默认情况下都归属于window 对象,window 对象是全局唯一的,在访问其属性和方法的时候,可以省略掉 "window." 前缀
(2)window 对象常用的属性:
document:文档对象,比如 document.write(内容) 等效于 window.document.write(内容)。
location:代表浏览器地址栏中的 url 地址
history:浏览器的历史记录
示例:


(3)window 对象的常用方法
alert():弹出提示框
prompt(提示信息):弹出输入框
var res = setInterval(函数, 定时时间):定时器,周期性的执行函数的代码,定时时间为毫秒记
clearInterval(res):关闭定时器
var res = setTimeout(函数,到期时间):设置一个到期时间之后执行一次函数就退出
clearTimeout(res):关闭Timeout
示例:轮播图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo33</title>
<style>
*{
margin: 0;
padding: 0;
}
div.box{
width: 600px;
height: 450px;
margin: 40px auto;
border: 2px solid #ccc;
}
div.box > img{
width: 600px;
height: 450px;
}
</style>
</head>
<body>
<div class="box">
<img src="images/1.jpg" alt="" id="img">
</div>
<script>
var i = 0;//全局变量
//获取 img 这个 dom 对象
var img = document.getElementById("img");
//定时器:第一个参数为周期执行的函数,第二个参数为定时时间,毫秒记
setInterval(function () {
//重新给 img 这个 dom 对象的 src 属性赋值,切换图片
img.src = "images/" + ++i + ".jpg";
if(i >= 4){ //总共4副图片
i = 0;
}
}, 1000);
</script>
</body>
</html>

4.访问 HTML 元素(DOM对象)
(1)访问 HTML 元素有两种方式
① 使用 document 对象提供的方法来获取对应的 DOM 对象
② 利用 DOM 树的节点关系来访问
(2)使用 document 对象的方法来访问,window 对象的 document 对象提供了如下的方法来找到 HTML 元素(DOM对象)
① document.getElementById(idVal):根据HTML元素的id值来找到该DOM对象。
② document.getElementsByName(name):根据HTML元素的name属性来找到该DOM对象的集合。
③ document.getElementsByClassName(className):根据HTML元素的class名称找到该DOM对象的集合
④ document.getElementsByTagName(tagName):根据HTML元素的标签名找到该DOM对象的集合
⑤ document.querySelector(CSS选择器):通过CSS选择器返回DOM对象
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo34</title>
</head>
<body>
<div id="mdiv" style="border: 1px solid #ccc;"></div>
<input type="text" name="info" id="info">
<p id="mp">一个段落</p>
<script>
//找到 id=mdiv 的 dom 对象
let mdiv = document.getElementById("mdiv");
//设置 dom 对象的属性
/**
* dom 对象常用属性:
* innerHTML:获取或设置 dom 对象内部的 HTML 片段
* innerText:获取或设置 dom 对象内部的文本内容
*/
mdiv.innerHTML = "<h1>新增的h1标签</h1>";
//mdiv.innerText = "<h1>新增的h1标签</h1>";
//找到 info 这个 dom
var info = document.getElementById("info");
//设置 info 对象的 value 属性:
info.value = "我是通过 js 代码设置的 value 值";
/**
* 我们除了可以使用 dom 对象的原生属性之外,还可以通过 dom.setAttribute(属性名, 属性值) 来设置 dom 的属性值,通过
* dom.getAttribute(属性名) 来获取 dom 对象的属性值,并且该方式可以设置自定义的属性
*/
var mp = document.getElementById("mp");
mp.innerText = "我是通过 js 添加的文本";
//添加一个自定义属性
//mp.test = "测试";
mp.setAttribute("test","测试");
</script>
</body>
</html>

(3)利用节点关系访问 HTML 元素
① Node parentNode:返回当前节点的父节点
② Node previousNode:返回当前节点的前一个兄弟节点
③ Node nextSibling:返回当前节点的下一个兄弟节点
④ Node[] childNodes:返回当前节点的所有孩子节点
⑤ Node firstChild:返回当前节点的第一个孩子节点
⑥ Node lastChild:返回当前节点的最后一个孩子节点
示例:


(4)节点的修改:这里的修改我们主要指对元素节点的操作。
① 创建节点:document.createElement(标签名)
② 删除节点:父节点.removeChild(子节点)
③ 替换节点:父节点.replaceChild(新节点 , 旧节点)
④ 插入节点
父节点.appendChild(子节点)
父节点.insertBefore(新节点 , 旧节点)
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo57</title>
</head>
<body>
<div class="mf">
<!--javascript:void(0):禁用表单提交-->
<form action="javascript:void(0)" id="mf">
编号:<input type="text" name="id"> <br>
姓名:<input type="text" name="name"> <br>
年龄:<input type="text" name="age"> <br>
性别:<input type="text" name="sex"> <br>
工资:<input type="text" name="sal"> <br>
<input type="submit" value="增加">
</form>
</div>
<hr>
<div class="mt">
<table border="1" cellspacing="0" cellpadding="0" id="mt">
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>工资</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script>
var myform = document.getElementById("mf");
var mytable = document.getElementById("mt");
//表单的提交事件:当表单提交的时候,执行后面的匿名函数
myform.onsubmit = function () {
//找到所有的 input 元素
let inputs = this.getElementsByTagName("input");
var id = inputs[0].value;
var name = inputs[1].value;
var age = inputs[2].value;
var sex = inputs[3].value;
var sal = inputs[4].value;
//通过表格对象找到 tbody 这个 dom 对象
let tbody = mytable.querySelector("tbody");
let tr = document.createElement("tr");//创建一个表格行
//表格行内容指定 HTML 片段
tr.innerHTML = "<td>"+id+"</td>" + "<td>"+name+"</td>" + "<td>"+age+"</td>" + "<td>"+sex+"</td>" +
"<td>"+sal+"</td>" + "<td><a href='javascript:void(0)'>删除</a></td>";
tbody.append(tr);//将包含了数据的表格行附加给 tbody 对象
//找到了当前行的最后一个孩子的孩子:就是"删除"这个 a 标签,给其添加一个单击事件
tr.lastChild.childNodes[0].onclick = function () {
//this在这里指的就是发生单击事件的 a 标签
this.parentNode.parentNode.remove();//将a的父元素的父元素 tr 本身删除
}
}
</script>
</body>
</html>

5.DOM 事件模型
(1)JavaScript 在浏览器中运行,浏览器中的 HTML 元素主要由 DOM 元素组成,这些 DOM 对象也会对应到各种 HTML 元素,我们可以为这些 DOM 对象添加事件处理函数,当某个 DOM 对象(HTML元素)发生对应的事件的时候,那么对应的事件函数就会自动被调用。
(2)HTML 元素的事件可以由事件属性来指定,事件属性是以事件类型加上一个 "on" 前缀来组成的,比如:onclick,onfocus 等等,这些属性名被称为事件处理器,属性值就是对应的事件处理函数,当事件发生时,对应的事件函数就自动被调用。
示例:


(3)绑定 DOM 对象的属性来绑定事件函数:
示例:找到某个 DOM 对象,给其事件属性指定事件函数


6.标准的 HTML 文档元素支持的事件:

示例1:变化表格的背景颜色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo39</title>
<style>
*{
margin: 0;
padding: 0;
text-align: center;
}
.wrap {
width: 500px;
margin: 100px auto 0;
}
table{
border-collapse: collapse;/*单元格之间没有间距*/
border-spacing: 0; /*单元格之间间距为0*/
border: 1px solid #c0c0c0;
width: 500px;
}
th,td{
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}
th{
background-color: #09c;
font: bold 16px "微软雅黑";
color: #fff;
}
tbody tr{
background-color: #f0f0f0;
cursor: pointer;
}
.current {
background-color: red!important; /*不能继承父元素的颜色,必须为红色*/
}
</style>
</head>
<body>
<div class="wrap">
<table>
<thead>
<tr>
<th>序号</th>
<th>姓名</th>
<th>课程</th>
<th>成绩</th>
</tr>
</thead>
<tbody id="target">
<tr>
<td>1</td>
<td>吕不韦</td>
<td>语文</td>
<td>100</td>
</tr>
<tr>
<td>2</td>
<td>吕布</td>
<td>日语</td>
<td>100</td>
</tr>
<tr>
<td>3</td>
<td>吕蒙</td>
<td>营销学</td>
<td>100</td>
</tr>
<tr>
<td>4</td>
<td>吕尚</td>
<td>数学</td>
<td>100</td>
</tr>
<tr>
<td>5</td>
<td>吕雉</td>
<td>英语</td>
<td>100</td>
</tr>
<tr>
<td>6</td>
<td>吕超</td>
<td>体育</td>
<td>100</td>
</tr>
</tbody>
</table>
</div>
<script>
//各行变色
var tbody = document.getElementById("target");
var trArr = tbody.children;//找到 tbody 的所有孩子,即所有的 tr,不包含 td
for (let i = 0; i < trArr.length; i++) {
if(i % 2 == 0){
trArr[i].style.backgroundColor = "#a3a3a3";
}else {
trArr[i].style.backgroundColor = "#ccc";
}
//鼠标进入 tr 的时候高亮,离开后正常
var color = "";
//鼠标悬停修改 tr 背景色
trArr[i].onmouseover = function () { //给所有的 tr 绑定鼠标悬停事件
//在赋值之前,先记录原来的颜色
color = this.style.backgroundColor;//this 在这里指的是发生该事件的对象 tr
//将发生事件的 tr 的颜色修改
this.style.backgroundColor = "#fff";
}
//鼠标移出去的时候恢复原来的颜色
trArr[i].onmouseout = function () {
this.style.backgroundColor = color;
}
}
</script>
</body>
</html>

示例2:将左边 select 下拉框选中的元素移动到右边的 select 下拉框中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo40</title>
<style>
select{
width: 170px;
height: 200px;
font-size: 16px;
background-color: #a4ff43;
}
</style>
</head>
<body>
<select name="sel1" id="sel1" size="10" multiple>
<option value="0">香蕉</option>
<option value="1">苹果</option>
<option value="2">鸭梨</option>
<option value="3">葡萄</option>
</select>
<button>>>></button>
<button><<<</button>
<button>></button>
<button><</button>
<select name="sel2" id="sel2" size="10" multiple>
</select>
<script>
//需求1:点击 <<< 和 >>> 按钮时,所有的子元素跑到对方标签中
var sel1 = document.getElementById("sel1");
var sel2 = document.getElementById("sel2");
var btnArr = document.getElementsByTagName("button");
btnArr[0].onclick = function () { //第一个按钮 >>>
//获取所有 sel1 的元素,整体添加到 sel2 中
var arr = sel1.children;
for (let i = arr.length - 1;i >= 0; i--){
sel2.appendChild(arr[i]);
}
}
//同理,全部过来
btnArr[1].onclick = function () { //第二个按钮 <<<
//获取所有 sel2 的元素,整体添加到 sel1 中
var arr = sel2.children;
for (let i = arr.length - 1;i >= 0; i--){
sel1.appendChild(arr[i]);
}
}
//需求2:点击 > 和 < 按钮时,选中的元素跑到对方,提示:option 有一个属性 selected,如果为 true,表示选中
btnArr[2].onclick = function () { //第三个按钮 >
//获取所有 sel1 的元素,选中的添加到 sel2 中
var arr = sel1.children;
for (let i = arr.length - 1;i >= 0; i--){
if (arr[i].selected === true)
sel2.appendChild(arr[i]);
}
}
btnArr[3].onclick = function () { //第四个按钮 <
//获取所有 sel2 的元素,选中的添加到 sel1 中
var arr = sel2.children;
for (let i = arr.length - 1;i >= 0; i--){
if (arr[i].selected === true)
sel1.appendChild(arr[i]);
}
}
</script>
</body>
</html>

7.DOM 事件模型
(1)DOM 也提供了事件模型:
通过 addEventListener('eventType',handler,captureFlag) 方法监听事件,其中 'eventType' 表示事件的名称,就是属性事件去掉 on 即可,handler 是事件函数,事件发生时触发,captureFlag 表示监听事件的阶段,true 表示捕获阶段,false 表示冒泡阶段,默认是 false。
示例:


(2)当事件发生时,会自动创建一个 Event 事件对象,并传递给事件函数作为参数,Event 接口中主要定义了如下属性:
① type:返回事件的类型,比如 click,mouseover 等等
② target:触发事件的事件源
③ currentTarget:返回事件当前所在的事件源
④ button:返回一个数字,代表出发事件的鼠标键,0 表示左键,1 表示中键,2 表示右键
⑤ altKey,ctrlKey,metaKey,shiftKey:分别代表事件发生时是否同时按下了alt,ctrl,meta,shift 键
⑥ clientX,clientY:返回事件发生时的鼠标的位置,以浏览器窗口为坐标系
⑦ screenX,screenY:返回事件发生时的鼠标的位置,以显示器为坐标系
⑧ offsetX,offsetY:返回事件发生时的鼠标的位置,以父元素作为坐标系
示例:

(3)事件传播
DOM 事件发生之后,会进行传播,会经历两个阶段,第一个阶段称为事件捕获阶段,事件从最顶层元素依次往下传播,直到传播到最底层元素,接着进入第二个阶段:事件冒泡阶段,事件传播从底层依次上溯,直到达到顶层的元素为止,如下图:

监听事件的函数 addEventListener() 方法的第三个参数可以指定是去监听捕获阶段(true),还是监听冒泡阶段(false,默认)。为了阻止事件传播,可以使用 Event 对象的 stopPropagation() 方法来阻止事件传播。
示例1:监听冒泡阶段(默认情况)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo43</title>
<style>
*{
margin: 0;
padding: 0;
}
.p{
width: 400px;
height: 400px;
background-color: blue;
}
.s{
width: 300px;
height: 300px;
background-color: red;
}
.ss{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="p">
父 DIV
<div class="s">
儿子 DIV
<div class="ss">
孙子 DIV
</div>
</div>
</div>
<script>
var p = document.querySelector(".p");//父元素
var s = document.querySelector(".s");//子元素
var ss = document.querySelector(".ss");//孙子子元素
//addEventListener 默认情况下就是监听冒泡阶段
p.addEventListener("click",function () {
console.log("父元素被点击");
});
s.addEventListener("click",function () {
console.log("子元素被点击");
});
ss.addEventListener("click",function () {
console.log("孙子元素被点击");
});
</script>
</body>
</html>


从执行的结果可知,冒泡阶段事件传播的顺序是:孙子元素被点,然后是儿子元素,最后是父元素
示例2:监听捕获阶段
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo43</title>
<style>
*{
margin: 0;
padding: 0;
}
.p{
width: 400px;
height: 400px;
background-color: blue;
}
.s{
width: 300px;
height: 300px;
background-color: red;
}
.ss{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="p">
父 DIV
<div class="s">
儿子 DIV
<div class="ss">
孙子 DIV
</div>
</div>
</div>
<script>
var p = document.querySelector(".p");//父元素
var s = document.querySelector(".s");//子元素
var ss = document.querySelector(".ss");//孙子子元素
//addEventListener 第三个参数为 true 就是监听捕获阶段
p.addEventListener("click",function () {
console.log("父元素被点击");
},true);
s.addEventListener("click",function () {
console.log("子元素被点击");
},true);
ss.addEventListener("click",function () {
console.log("孙子元素被点击");
},true);
</script>
</body>
</html>

监听捕获阶段,事件传播的顺序:父元素,然后子元素,最后孙子元素
示例3:阻止事件传播:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo43</title>
<style>
*{
margin: 0;
padding: 0;
}
.p{
width: 400px;
height: 400px;
background-color: blue;
}
.s{
width: 300px;
height: 300px;
background-color: red;
}
.ss{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="p">
父 DIV
<div class="s">
儿子 DIV
<div class="ss">
孙子 DIV
</div>
</div>
</div>
<script>
var p = document.querySelector(".p");//父元素
var s = document.querySelector(".s");//子元素
var ss = document.querySelector(".ss");//孙子子元素
//addEventListener 默认就是监听冒泡阶段
p.addEventListener("click",function () {
console.log("父元素被点击");
});
s.addEventListener("click",function () {
console.log("子元素被点击");
});
ss.addEventListener("click",function (e) {//e 就是 Event 对象
console.log("孙子元素被点击");
e.stopPropagation();//阻止事件传播
});
</script>
</body>
</html>

可以发现,当我们点击孙子元素时,只有孙子元素响应了事件,事件被阻止了,没有继续往上传播。
综合案例:祝愿墙
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>祝愿墙</title>
<style>
body {
margin: 0 auto;
padding: 0px;
font-size: 12px;
background: url("images/bg.gif") repeat center 36px;
text-align: center;
background-color: #c30230;
}
#content {
margin: 0 auto;
width: 960px;
background: url("images/content_bg.jpg") no-repeat left top;
height: 627px;
position: relative;
}
#content .tip0, #content .tip1, #content .tip2, #content .tip3, #content .tip4, #content .tip5, #content .tip6, #content .tip7, #content .tip8 {
position: absolute;
width: 227px;
left: 200px;
top: 100px;
}
#content .tip_h {
background: url("images/tip1_h.gif") no-repeat left top;
width: 227px;
padding-top: 45px;
height: 23px;
text-align: left;
cursor: move;
}
#content .tip_c {
background: url("images/tip1_c.gif") repeat-y;
width: 200px;
padding-left: 12px;
padding-right: 15px;
min-height: 40px;
text-align: left;
line-height: 20px;
max-height: 160px;
word-wrap: break-word; /*强制长单词在其容器宽度不足时自动换行*/
word-break: break-all; /*允许在单词内换行*/
overflow: hidden;
}
#content .tip_f {
background: url("images/tip1_f.gif") no-repeat left top;
width: 227px;
height: 53px;
padding-top: 20px;
}
#content .num {
float: left;
padding-left: 7px;
width: 195px;
}
#content .close {
float: left;
font-size: 12px;
cursor: pointer;
color: #000000;
}
.clr {
clear: both;
overflow: auto;
display: block;
height: 0px;
}
#content .icon {
float: left;
width: 35px;
padding-left: 15px;
height: 35px;
text-align: center;
}
#content .name {
float: right;
padding-right: 15px;
text-align: right;
font-size: 14px;
line-height: 35px;
color: #C0F;
}
</style>
</head>
<body>
<!--纸条墙-->
<div id="content">
</div>
<script>
//模拟数据库,获取信息
var messages = [
{"id":1,"name":"mahu","content":"今天你拿苹果支付了么","time":"2016-02-17 00:00:00"},
{"id":2,"name":"haha","content":"今天天气不错,风和日丽的","time":"2016-02-18 12:40:00"},
{"id":3,"name":"jjjj","content":"常要说的事儿是乐生于苦","time":"2016-03-18 12:40:00"},
{"id":4,"name":"9.8的妹纸","content":"把朋友家厕所拉堵了 不敢出去 掏了半小时了都","time":"2016-03-18 12:40:00"},
{"id":5,"name":"雷锋ii.","content":"元宵节快乐","time":"2016-02-22 12:40:00"},
{"id":6,"name":"哎呦哥哥.","content":"据说今晚央视的元宵晚会导演和春晚导演是同一个人,真是躲得过初一,躲不过十五。","time":"2016-02-22 01:30:00"},
{"id":7,"name":"没猴哥,不春晚","content":"班主任:"小明,你都十二岁了,还是三年级,不觉得羞愧吗"?。小明:"一点也不觉得,老师你都四十多岁了,不也是年年在三年级混日子吗?羞愧的应该是你"。老师:......","time":"2016-02-22 01:30:00"},
{"id":8,"name":"哎呦杰杰.","content":"真搞不懂你们地球人,月亮有什么好看的,全是坑,还是对面那哥们好看,","time":"2016-02-22 01:30:00"},
{"id":9,"name":"哎呦哎呦","content":"今天哪里的烟花最好看!!?答:朋友圈。。。","time":"2016-02-22 02:30:00"}
];
//需求1:模拟数据库获取信息,然后在页面上生成数组的长度个tip,然后分别填充内容。
//需求2:点击内容,提高层级;点击关闭按钮,删除tip标签;双击顶部,删除标签.....
//步骤:
//获取相关元素
var content = document.getElementById("content");
//循环生成div标签,然后为innerHTML属性添加内容
for(var i=0;i<messages.length;i++){
//生成新标签
var newDiv = document.createElement("div");
//绑定类名和ID
newDiv.className = "tip" + i;
newDiv.id = "tip" + messages[i].id;
//改变位置
var topValue = parseInt(Math.random()*400);
var leftValue = parseInt(Math.random()*700);
newDiv.style.top = topValue+"px";
newDiv.style.left = leftValue+"px";
//赋值内容
newDiv.innerHTML = '<div class="tip_h" title="双击关闭纸条">'+
'<div class="num">第[49568]条 '+messages[i].time+'</div>'+
'<div class="close" title="关闭纸条" >×</div>'+
'<div class="clr"></div>'+
'</div>'+
'<div class="tip_c">'+
messages[i].content +
'</div>'+
'<div class="tip_f">'+
'<div class="icon">'+
'<img src="images/bpic_1.gif" alt="" title="">'+
'</div>'+
'<div class="name">'+messages[i].name+'</div>'+
'<div class="clr"></div>'+
'</div>';
//把新创建的元素放入content里面
content.appendChild(newDiv);
//绑定事件,提高层级
var index = 1;
newDiv.onclick = function () {
this.style.zIndex = index;
index++;
};
//点击关闭按钮的时候关闭父盒子。
var closeDiv = newDiv.getElementsByClassName("close")[0];
closeDiv.onclick = function () {
//this就是 close这个div
content.removeChild(this.parentNode.parentNode);
}
//双击关闭按钮类名叫做tip_h
var dbDiv = newDiv.getElementsByClassName("tip_h")[0];
dbDiv.ondblclick = function () {
//this 就是值 tip_h
content.removeChild(this.parentNode);
}
}
</script>
</body>
</html>

九、AJAX
1、AJAX概述
(1)什么是Ajax ?
AJAX(Asynchronous JavaScript and XML)是一种能够让前端网页和后台Web服务器进行异步交互的技术,可以实现页面局部刷新(可以不用去加载整个页面而实现页面的局部刷新)。AJAX 的主要作用是让网页能与服务端进行数据异步交互,我们能够使用 HTML+AJAX 能够代替 JSP,实现网页上数据的动态展示。
(2)什么是异步交互?
异步交互是指能够让客户端发送一个请求后,不需要等待服务端的结果的返回,随时能够再次发送下一个请求。网页能够局部刷新就是利用了异步交互技术。而同步交互需要等待服务端响应数据后,才能发送下一个请求,所以使用同步交互的网页需要手动刷新。

(3)AJAX的优点:
1)提高网页的动态性。AJAX技术能让网页实现局部刷新,能够极大提高网页的动态性
2)提高用户体验。Ajax技术是一种异步交互技术,用户浏览器不必等待请求结果就能再次发送请求,大大提高用户体验,同时能够为用户提供搜索提示,验证提示
3)AJAX可使网页小程序更小、更快,更友好
2. 核心对象
XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的
使用步骤:
(1)创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
(2)设置请求信息
//method表示请求后台服务器的方式:get或post等等方式,url:请求后台服务器的地址
xhr.open(method, url); //打开与后台服务器的连接
(3)发送请求
xhr.send(body)//get请求不传body参数,只有 post 请求要传 body
(4)接收响应

3. AJAX 快速入门:
(1)后台服务器:
基于 Servlet 的 Web 应用程序:Servlet 是部署在 HTTP 服务器(Tomcat服务器)的一个组件,专门用于响应用户的请求。
1)创建 JavaWeb 项目:

上面配置好的 Tomcat 是这样配置的


然后点击"下一步":

然后点击"Finish"就生成后台 Web 工程了,如下:

2)导入 gson.jar 包:
将后台的数据转换成前端能够接受的 JSON 数据,因为我们前后端交互使用 JSON 对象进行交互
a. WEB-INF 目录下新建 lib 目录,将 gson.jar 拷贝进去

b. 右键 lib 目录,将整个 lib 目录中的 jar 包添加为工程的库:Add As Library


3) 创建前后交互的 JavaBean:User

4) 创建后台组件 Servlet,跟前端进行交互
package com.edu.ctrl;
import com.edu.beans.User;
import com.google.gson.Gson;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
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.util.ArrayList;
import java.util.List;
@WebServlet("/userServlet") //该 Servlet 的后台 URL 地址
public class UserServlet extends HttpServlet {
//用于响应客户端的 GET 请求
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置请求和响应的字符编码为 UTF-8,保证通讯过程中可以使用中文
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//准备回送给客户端的数据
List<User> users = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
users.add(new User(i, "姓名" + i, 20 + i, i%2==0?"男":"女"));
}
//产生 gson 对象,使用 gson 将 users 对象转换为 json 格式的字符串,发送给前端
Gson gson = new Gson();
String s = gson.toJson(users);//将 users 对象转换为 json 格式的字符串
PrintWriter out = response.getWriter();
out.write(s);//将 json 字符串写给客户端
out.flush();//刷新流
}
//用于响应客户端的 POST 请求
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
(2) 在工程的 webapp 目录下创建前端页面 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<table border="1" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
//1. 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
//2. 发送请求
//2.1 确定请求方式和请求后台的地址
xhr.open("GET","userServlet");
//2.2 发送请求到后台
xhr.send();
//3. 获取后台响应数据
xhr.onreadystatechange = function () {
//3.1 判断服务器端对于浏览器的请求是否响应完成,并判断客户端是否成功收到响应数据
if(this.readyState == 4 && this.status == 200){
//将服务器发送过来的JSON字符串转换为JavaScript的JSON对象
let users = JSON.parse(this.responseText);//得到的 users 是一个 json 对象组成数组
var content = "";
for (let i = 0; i < users.length; i++) {
content += "<tr>";//行
content += "<td>" + users[i].id + "</td>" +
"<td>" + users[i].name + "</td>" +
"<td>" + users[i].age + "</td>" +
"<td>" + users[i].sex + "</td>" +
"<td><a href=''>删除</a><a href=''>更新</a></td>";
content += "</tr>";
}
}
var tbody = document.querySelector("table tbody");
tbody.innerHTML = content;
}
</script>
</body>
</html>
(3) 部署 Web 应用程序到 Tomcat 服务器中运行:



然后部署应用:


然后点击启动按钮启动 Tomcat 服务器:

结果:

我们实现的是局部刷新,JS 代码只改动了表格的 tbody 部分,其他地方没有变,是属于异步的通讯方式,效率极高。