一. 什么是AJAX
简单来说,AJAX就是用JS发请求,收响应。
AJAX是浏览器上的一个功能。原本浏览器可以发请求,收响应,现在想把这个功能暴露出来给JS开发者。怎么做呢?浏览器在window上挂了一个XMLHttpRequest函数。window.XMLHttpRequest是一个构造函数,它可以构造出一个HttpRequest对象,JS通过这个对象来实现发请求,收响应。
二. 准备一个服务器
既然要发请求和收响应,就需要一个服务器接收响应。用server.js模拟。为了修改代码不需要重启,我们使用 node-dev 代替 node。运行:
node-dev server.js 8888
就会监听8888端口,一旦浏览器向8888端口发送请求,就会运行server.js文件一次。
//server.js
console.log("有个傻子发请求过来啦!路径(带查询参数)为:" + pathWithQuery);
if (path === "/index.html") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/html;charset=utf-8");
//把文件读成字符串的形式
response.write(fs.readFileSync("public/index.html"));
response.end();
} else if (path === "/main.js") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
response.write(fs.readFileSync("public/main.js"));
response.end();
} else if (path === "/style.css") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/css;charset=utf-8");
response.write(fs.readFileSync("public/style.css"));
response.end();
} else if (path === "/2.js") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
response.write(fs.readFileSync("public/2.js"));
response.end();
} else if (path === "/3.html") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.write(fs.readFileSync("public/3.html"));
response.end();
} else {
response.statusCode = 404;
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.write(`你访问的页面不存在`);
response.end();
}
用if else,根据请求的不同路径名,有不同的响应内容。每个if 可看成是一个路由。
我们先请求index.html路径,根据第一个if语句,服务器的响应内容是index.html文件。index.html里引用了main.js文件。
原来我们请求css和js文件的做法:在index.html里用link标签和script标签直接引入css和js。
现在我们使用AJAX请求。在main.js文件里请求。
三. 加载CSS
以前用<link rel="stylesheet" href="/style.css" />,现在用AJAX加载CSS。
四个步骤:
- 创建HttpRequest对象
- 调用对象的open方法(初始化对象)
- 监听对象的onload,onerror事件(加载成功怎么样,加载失败怎么样)
- 调用对象的send方法(发送请求)
代码实现:
//main.js
getCSS.onclick = () => { //为了看清楚变化,点击按钮才会加载
const request = new XMLHttpRequest();
request.open("GET", "/style.css");
request.onload = () => {
console.log("request.response");
console.log(request.response);
//创建一个style标签
const style = document.createElement("style");
//填写style内容
style.innerHTML = request.response;
//插到head里
document.head.appendChild(style);
};
request.onerror = () => {
console.log("失败了");
};
request.send();
};
如果加载成功了,就会调用onload事件,查看开发者工具-Network,可以看到接收到的响应。打印出request.response,它就是响应的内容,字符串。

四. 加载JS
以前用 <script src="/2.js"></script> ,现在用AJAX加载JS。
还是和加载CSS同样的方法,四个步骤。
//main.js
getJS.onclick = () => {
const request = new XMLHttpRequest();
request.open("GET", "/2.js");
request.onload = () => {
//创建script标签
const script = document.createElement("script");
//填写script内容
script.innerHTML = request.response;
//插到body里
document.body.appendChild(script);
};
request.onerror = () => {};
request.send();
};
//2.js
console.log("我是2.js");
五. 加载html
以前我们不用AJAX,可以通过link和script引用css和js文件。但是以前我们不会加载3.html。
//3.html
<div style="border:1px solid red;width:300px;height:300px;">
动态内容
</div>
加载成功,会显示一个div。
//main.js
getHTML.onclick = () => {
const request = new XMLHttpRequest();
request.open("GET", "/3.html");
request.onload = () => {
//创建一个div
const div = document.createElement("div");
//填写div的内容 request.response就是一个字符串,请求的那个内容
div.innerHTML = request.response;
//插到body里
document.body.appendChild(div);
};
request.onerror = () => {};
request.send();
};

//index.html
<!DOCTYPE html>
<head>
<title>ajax</title>
<!--<link rel="stylesheet" href="/style.css" />-->
</head>
<body>
<h1>AJAX demo</h1>
<p>
<button id="getCSS">请求CSS</button>
<button id="getJS">请求JS</button>
<button id="getHTML">请求HTML</button>
</p>
<script src="/main.js"></script>
<!--<script src="/2.js"></script>-->
</body>
六. onreadystatechange 事件
只要 readyState 属性发生变化,就会调用相应的处理函数。
一个请求对象的readyState属性代表了一个请求的一生:有五种返回值:
- 0:一个请求被创建了 const request=new XMLHttpRequest()
- 1:调用了open方法
- 2:调用了send方法
- 3:正在下载响应体
- 4:全部下载完成
专业前端会将onload,onerror事件改为 onreadystatechange 事件。因为onerror事件不够用,如果我故意写错请求的路径,会发现浏览器会加载服务器中判断是未知路径的响应内容。而不会调用onerror事件,也就是说,onerror没用。
getCSS.onclick = () => {
const request = new XMLHttpRequest();
request.open("GET", "/style.css");
request.onreadystatechange = () => {
console.log(request.readyState);
if (request.readyState === 4) {
console.log("下载完成");
if (request.status >= 200 && request.status < 300) {
//创建一个style标签
const style = document.createElement("style");
//填写style内容
style.innerHTML = request.response;
//插到head里
document.head.appendChild(style);
} else {
alert("请求失败");
}
}
};
request.send();
};
我们只关心响应体下载完成后,也就是request.readyState===4。但是下载完成了,可能是请求成功,把正确的响应体下载完成。也有可能是请求失败,把404页面下载完成。也就是说,如果故意写错请求路径,会把服务器里的最后一个else语句里的响应体响应回来,还是会打印出下载完成。那怎么区分成功和失败呢?所以在下载完成的情况下,要判断request的状态码status,如果是200-300,就说明请求成功。否则,就说明请求失败,用alert弹出提示。
这里,request.status是指请求得到的响应的状态码。
七. 加载XML
AJAX一开始就是为了加载XML的,有一个request.responseXML方法,可以直接返回这个DOM对象。
getXML.onclick = () => {
const request = new XMLHttpRequest();
request.open("GET", "/4.xml");
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 300) {
console.log(request.responseXML);
const dom = request.responseXML;
const text = dom.getElementsByTagName("warning")[0].textContent;
console.log(text.trim());
}
}
};
request.send();
};
//4.xml
<?xml version="1.0" encoding="UTF-8"?>
<message>
<warning>
Hello World
</warning>
</message>
八. 加载JSON
1. 什么是JSON?
JavaScript Object Notation ,JS对象标记语言。是一门独立的语言。 JSON只支持六种数据类型:(没有函数,变量等)
- string,只支持双引号
- number
- bool:true,false
- null
- object
- array
可查看json.org官网
2. window.JSON
是一个全局对象

-
JSON.parse:
将符合JSON语法规范的字符串转换成JS对应类型的数据(可 以是对象, 数字,布尔值等)。
如果不符合JSON语法,会抛出一个Error对象。一般用try catch捕获错误。
把要写的代码放进try,如果没有错误,给obj赋值;如果捕获到错误了,就打印出error,给obj一个保底值。因为我们并不能保证parse里的一定符合字符串规范,所以一般都要用try catch。
-
JSON.stringify:
把JS数据转换成符合JSON语法规范的字符串
3. 加载JSON
用JSON.parse获取到响应的内容,然后对它进行操作。所有request.response都是所获取到的文件里的内容,类型是字符串。
getJSON.onclick = () => {
const request = new XMLHttpRequest();
request.open("GET", "/5.json");
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 300) {
console.log(request.response);
const obj = JSON.parse(request.response); //把符合JSON语法的字符串转换成对象或其他东西
myName.innerText = obj.name;
}
}
};
request.send();
};
//index.html
<body>
<h1>AJAX hello <span id="myName"></span></h1>
<p>
<button id="getJSON">请求JSON</button>
</p>
<script src="/main.js"></script>
</body>
//5.json
{
"name": "anqi",
"age": 18
}
点击按钮,就会在页面的hello 后边显示json文件定义的对象的name属性值。
九. 模拟分页
新建一个db目录,有三个文件,page1.json,2,3。分别是有十个对象数据的数组。想要实现:在浏览器页面里展示page1.json的内容,然后点击页面里的按钮,可以继续加载page2.json和page3.json的内容。
- 先是加载page1.json,不用ajax。
//server.js
if (path === "/index.html") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/html;charset=utf-8");
//把文件读成字符串的形式
let string = fs.readFileSync("public/index.html").toString();
//在html里设一个占位符,然后从数据库获取这个数据,替代占位符
const page1 = fs.readFileSync("db/page1.json");
const array = JSON.parse(page1);
const result = array.map(item => `<li>${item.id}</li>`).join("");
string = string.replace("{{page1}}", `<ul id='ul'>${result}</ul>`);
response.write(string);
response.end();
}
//index.html
<div>
{{page1}}
</div>
做法:在index.html里写一个div标签,放一个占位符。在服务器代码里,如果请求了index.html,先以字符串形式读出page1.json的内容,然后用string.replace方法,把页面里的占位符替换成page1。这样,页面就会显示page1里定义的数组。
- AJAX加载其余分页:
//main.js
let n = 2;
getPAGE.onclick = () => {
const request = new XMLHttpRequest();
request.open("GET", `/page${n}.json`);
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 300) {
const arr = JSON.parse(request.response);
arr.forEach(x => {
const li = document.createElement("li");
li.innerText = x.id;
ul.appendChild(li);
});
n += 1;
}
}
};
request.send();
};
同上,点击按钮,触发AJAX的事件,如果请求成功,先用JSON.parse获取到响应的内容,这里是一个数组。然后DOM操作,把内容渲染到页面,对数组中的每个元素,创建li元素,插入文本,把li插到ul中,在页面显示。为了再次点击按钮,继续加载下一个分页,用变量n控制加载哪个文件里的数据。每次事件结束,n自动+1。