概述
Web程序最初的目的就是将信息(数据)放到公共的服务器,让所有网络用户都可以通过浏览器访问。
在此之前,我们可以通过以下几种方式让浏览器发出对服务端的请求,获得服务端的数据:
●地址栏输入地址,回车,刷新
●特定元素的href或src属性
●表单提交
这些方案都是我们无法通过或者很难通过代码的方式进行编程(对服务端发出请求并且接受服务端返回的响应),如果我们可以通过JavaScript直接发送网络请求,那么Web的可能就会更多,随之能够实现的功能也会更多,至少不再是”单机游戏”。
AJAX( Asynchronous JavaScript and XML ) ,(先前是服务器返回XML,现在返回的是JSON格式,所以实际上该技术是AJAJ) 最早出现在2005年的Google Suggest (就是搜索框下的建议列表),是在浏览器端进行网络编程(发送请求、接收响应)的技术方案,它使我们可以通过JavaScript直接获取服务端最新的内容而不必重新加载页面。让Web更能接近桌面应用的用户体验。
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
说白了, AJAX就是浏览器提供的一套API ,可以通过JavaScript调用,从而实现通过代码控制请求与响应。实现网络编程。能力不够,API来凑。
AJAX发送请求
XMLHttpRequest:
程序必须先调用XMLHt tpRequest对象的responseText或responseXML来获取服务器响应,再通过DOM操作将服务器响应动态加载到当前页面中。
关于XMLHttpRequest最通用的定义是: XMLHttpRequest是一套可以在JavaScript、VBscript、JScript 等脚本语言中使用的API,它通过HTTP协议异步地向服务器发送请求,并获取从服务器返回的响应。
涉及到 ajax 操作的页面“不能”使用文件协议访问。(不能文件的方式访问)
(我放在了phpstudy_pro里www里的域名为ajax.learn 端口为8080的站点里
所以在网址输入ajax.learn:8080/ajax/ajax1.html就行了)
// 1.安装浏览器(浏览器相当于用户代理)
// xhr 就类似于浏览器的作用(发送请求接收响应)
var xhr = new XMLHttpRequest();
// 2. 打开浏览器,输入网址
xhr.open('GET', 'time.php');
// 3. 敲回车,开始请求
xhr.send(); //在检查里的network中all可查看向服务器请求回的
oneadytatechange事件中获取响应内容
// 1.安装浏览器(浏览器相当于用户代理)
// xhr 就类似于浏览器的作用(发送请求接收响应)
var xhr = new XMLHttpRequest();
// 2. 打开浏览器,输入网址
xhr.open('GET', 'time.php');
// 3. 敲回车,开始请求
xhr.send();
// 4. 等待响应
// 因为响应需要时间,所以无法通过返回值的方式返回响应 即不能console.log(xhr.send());
// 因为客户端永远不知道服务端何时才能返回我们需要的响应
// 所以AJAX API采用事件的机制(通知的感觉)
xhr.onreadystatechange = function () {
//这个事件并不是只在响应时触发, 状态改变就触发,(状态改变即创建xhr、open、send)
console.log(1); //所以打印了3个1
console.log(this.readyState); //2 3 4 因为每个状态对应一个数,0代表创建xhr,1代表open。。。 但是由于事件是后触发的,所以没有打印出全部,
//如果需要捕获第一个状态的变化,需要注意代码执行顺序的问题(不要出现来不及的情况)
}
time.php
<?php
echo time();
?>
readyState有五种可能的值:
0 (未初始化): (XMLHttpRequest)对象已经创建,但还没有调用open()方法。
1 (载入):已经调用open() 方法,但尚未发送请求。
2 (载入完成): 请求已经发送完成。
3 (交互):可以接收到部分响应数据。
4 (完成):已经接收到了全部数据,并且连接已经关闭。
// 1.安装浏览器(浏览器相当于用户代理)
// xhr 就类似于浏览器的作用(发送请求接收响应)
var xhr = new XMLHttpRequest();
console.log(xhr.readyState); // => 0 初始化,请求代理对象
// 2. 打开浏览器,输入网址
xhr.open('GET', 'time.php');
console.log(xhr.readyState); // => 1 open方法已经调用,建立一个与服务端特定端口的连接
// 3. 敲回车,开始请求
xhr.send();
// 4. 等待响应
// 因为响应需要时间,所以无法通过返回值的方式返回响应 即不能console.log(xhr.send());
// 因为客户端永远不知道服务端何时才能返回我们需要的响应
// 所以AJAX API采用事件的机制(通知的感觉)
xhr.onreadystatechange = function () {
//这个事件并不是只在响应时触发, 状态改变就触发,(状态改变即创建xhr、open、send)
// console.log(1); //所以打印了3个1
// console.log(this.readyState); //2 3 4
// switch (this.readyState) {
// case 2:
// console.log(this.readyState);
// // => 2 已经接受到了响应报文的响应头,即服务器名称信息等,但没有接受到响应体
// console.log(this.getAllResponseHeaders()); //打印响应头
// break;
// case 3:
// console.log(this.readyState);
// // => 3 正在下载响应报文的响应体,有可能为空、或不完整、或完整。
// break;
// case 4:
// console.log(this.readyState);
// // => 4 响应体下载完成
// break;
// }
if (this.readyState !== 4) return;
//若状态是4,则获取响应的内容
// console.log(this.readyState); //4
console.log(this.responseText); //1618626395 ,即我们请求的time.php中返回的数据
}
onload事件
var xhr = new XMLHttpRequest();
xhr.open('GET', 'time.php');
xhr.send();
// onl oad是HTML5 中提供的XMLHttpRequest version 2.0定义的,跟上述一样的功能
xhr.onload = function () {
console.log(this.readyState); //4
console.log(this.responseText); //1618630324
}
ajax遵循HTTP协议
var xhr = new XMLHttpRequest();
xhr.open('POST', 'add.php'); //设置请求行
xhr.setRequestHeader('Foo', 'Bar'); //设置一个请求头
// 一定注意 如果请求体是urlencoded格式必须设置这个请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('key1=value1&key2=value2'); //以urlencoded 格式设置请求体
add.php
<?php
var_dump($_POST);
?>
数据接口的概念
users1.php
<?php
// 返回的响应就是一个JSON 内容(返回的就是数据)
// 对于返回数据的地址一般我们称之为接口(形式上是Web信息)
$data = array(
array(
'id' => 1,
'name' => '束文波'
),
array(
'id' => 2,
'name' => '小夏'
),
array(
'id' => 3,
'name' => '米卡'
),
array(
'id' => 4,
'name' => '邢克垒'
)
);
if (empty($_GET['id'])) {
// 没有传ID,则获取全部
// 因为HTTP中约定报文的内容就是字符串,而我们需要传递给客户端的信息是-个有结构的数据
// 这种情况下我们一般采用JSON作为数据格式
$json = json_encode($data);// 格式:[{"id":1,"name":"束文波"},{...}]
echo $json;
} else {
// 传递了ID,只获取一条
foreach ($data as $item) { //循环遍历,
if ($item['id'] != $_GET['id']) continue; //找到对应的id对应的数组
$json = json_encode($item);
echo $json; //在地址栏设id=1,则打印出{"id":1,"name":"\u675f\u6587\u6ce2"} ,其中汉字是Unicode格式
}
}
发送GET请求并传递参数
var xhr = new XMLHttpRequest();
// 这里仍然是使用URL中的问号参数传递数据
xhr.open('GET', 'users.php?id=3'); //users.php在上面 在这里填京东啊,爱奇艺什么的相关数据接口,在下面即可获取内容
xhr.send(null);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
console.log(this.responseText); //{"id":3,"name":"\u7c73\u5361"}
}
发送GET请求并传递参数—小例子
user2.php
<?php
// 返回的响应就是一个JSON 内容(返回的就是数据)
// 对于返回数据的地址一般我们称之为接口(形式上是Web信息)
$data = array(
array(
'id' => 1,
'name' => '束文波',
'age' => 26
),
array(
'id' => 2,
'name' => '小夏',
'age' => 24
),
array(
'id' => 3,
'name' => '米卡',
'age' => 23
),
array(
'id' => 4,
'name' => '邢克垒',
'age' => 29
)
);
if (empty($_GET['id'])) {
// 没有传ID,则获取全部
// 因为HTTP中约定报文的内容就是字符串,而我们需要传递给客户端的信息是-个有结构的数据
// 这种情况下我们一般采用JSON作为数据格式
$json = json_encode($data); // 格式: [{"id":1,"name":"张三"},{...}]
echo $json;
} else {
// 传递了ID,只获取一条
foreach ($data as $item) { //循环遍历,
if ($item['id'] != $_GET['id']) continue; //找到对应的id对应的数组
$json = json_encode($item);
echo $json; //在地址栏设id=1,则打印出{"id":1,"name":"\u675f\u6587\u6ce2"} ,其中汉字是Unicode格式
}
}
实现:点击名字,弹出相应年龄。
<body>
<ul id="list"></ul>
<script>
var listElement = document.getElementById('list');
// 发送请求获取列表数据呈现在页面
var xhr1 = new XMLHttpRequest();
xhr1.open('GET', 'users1.php');
xhr1.send();
xhr1.onreadystatechange = function () {
if (this.readyState !== 4) return;
//使用 JSON.parse() 方法将请求到的 JSON 数据转换为 JavaScript 对象
var data = JSON.parse(this.responseText);
//循环遍历,为每个li注册点击事件
for (var i = 0; i < data.length; i++) {
// 创建多个元素li
var liElement = document.createElement('li');
// 给li标签设置内容为传过来的name的值
liElement.innerHTML = data[i].name;
liElement.id = data[i].id;
// 把li添加到ul中
listElement.appendChild(liElement);
// 为li注册点击事件
listElement.children[i].addEventListener('click', function () {
// 需要再请求个数据,返回本次点击的响应的数据
var xhr2 = new XMLHttpRequest();
// id为本次点击的名字的id
xhr2.open('GET', 'users2.php?id=' + this.id);
xhr2.send();
xhr2.onreadystatechange = function () {
if (this.readyState !== 4) return;
var data2 = JSON.parse(this.responseText);
// 弹出相应名字的年龄
alert(data2.age);
}
})
}
}
</script>
</body>
发送POST请求
POST请求过程中,都是采用请求体承载需要提交的数据。
如: xhr.send(‘username=KaTeX parse error: Expected 'EOF', got '&' at position 11: {username}&̲password={password}’);
login.php
<?php
// 接收用户提交的用户名和密码
if (empty($_POST['username']) || empty($_POST['password'])) {
exit('请提交用户名和密码');
}
//校验
$username = $_POST['username'];
$password = $_POST['password'];
if ($username == '蜡笔小新' && $password == 'ilovexiaogege') {
exit('成功登录');
}
exit('用户名或密码错啦');
?>
实现 点击登录按钮,显示加载层,加载完成后,打印结果
<style>
.loading {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgb(128, 125, 125);
opacity: 0.5;
text-align: center;
line-height: 500px;
font-size: 50px;
display: none;
}
.loading::after {
/*::after用来创建一个伪元素,作为已选中元素的最后一个子元素。这个虚拟元素默认是行内元素。 */
content: '加载中...';
color: #fff;
}
</style>
</head>
<body>
<div class="loading" id="loading"></div>
<table border="1">
<tr>
<td>用户名</td>
<td><input type="text" name="" id="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="" id="password"></td>
</tr>
<tr>
<td></td>
<td><button id="btn">登录</button></td>
</tr>
</table>
<script>
var btn = document.getElementById('btn');
var txtUsername = document.getElementById('username');
var txtPassword = document.getElementById('password');
var loading = document.getElementById('loading');
// 找一个合适的时机,做一件合适的事情
btn.onclick = function () {
//点击登录显示加载中。。。
loading.style.display = 'block';
// 1.获取界面上的元素 value
var username = txtUsername.value;
var password = txtPassword.value;
// 2.通过 XHR 发送一个 POST 请求
var xhr = new XMLHttpRequest();
xhr.open('POST', 'login.php');
// 一定注意 如果请求体是urlencoded格式必须设置这个请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('username=${username}&password=${password}');
// 3.根据服务端的反馈 做出界面提示
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
//加载完成
loading.style.display = 'none';
console.log(this.responseText); // 用户名或密码错啦
}
}
</script>
</body>
同步与异步
**同步:**一个人在同一个时刻只能做一件事情,在执行一些耗时的操作 ( 需要看管)不去做别的只是等待
**异步:**在执行一些耗时的操作(不需要看管)去做别的事,而不是等待
一般很少用同步。
//异步
console.time('aa');
var xhr = new XMLHttpRequest();
// open 方法的第三个参数是async异步 可以传入一个布尔值, 默认为true
xhr.open('GET', 'time.php', true);
xhr.send();
console.log(xhr.responseText); // 为空 因为异步是同时干好多事,send后的事在执行send时也在做
// 所以需要:xhr.onreadystatechange = function () 获得完整数据
console.timeEnd('aa'); // aa: 0.64208984375 ms
//同步
console.time('bb');
var xhr2 = new XMLHttpRequest();
// open 方法的第三个参数是async异步 可以传入一个布尔值, 默认为true
xhr2.open('GET', 'time.php', false);
xhr2.send();
// 同步是依次执行,所以不用xhr.onreadystatechange = function () 就能完整接收数据
console.log(xhr2.responseText); // 打印出1618828035
console.timeEnd('bb'); // bb: 21.026123046875 ms
所以很少用到 同步模式。
响应数据格式
XML
一种数据描述手段
老掉牙的东西,简单演示一下,不在这里浪费时间,基本现在的项目不用了。
淘汰的原因:数据冗余太多
JSON
也是一种数据描述手段,类似于JavaScript字面量方式
服务端采用JSON格式返回数据,客户端按照JSON格式解析数据。
不管是JSON也好,还是XML,只是在AJAX请求过程中用到,并不代表它们之间有必然的联系,它们只是数据协议罢了
处理响应数据渲染
模板引擎:
artTemplate : https://aui.github.io/art-template/
模板引擎实际上就是一个API, 模板引擎有很多种,使用方式大同小异,目的为了可以更容易的将数据渲染到HTML中
兼容方案:
XMLHttpRequest在老版本浏览器( IE5/6 )中有兼容问题,可以通过另外-种方式代替
var xhr = window. XMLHttpRequest ? new XMLHttpRequest() : new ActiveXobject(‘Mi crosoft.XMLHTTP’)
<body>
<table>
<tbody id="content"></tbody>
</table>
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'test.php');
xhr.send();
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
var res = JSON.parse(this.responseText);
var data = res.data;
for (var i = 0; i < data.length; i++) {
var tr = document.createElement('tr');
var td = document.createElement('td');
//下面方式太麻烦,我们采用模板引擎将数据呈现 artTemplate:https://aui.github.io/art-template/ 模板引擎实际上就是一个API
td.innerHTML = '<td>' + data[i].id + '</td>'
}
}
</script>
</body>