ajax详细介绍
远古时代的AJAX
需求:做一个在线投票,要求无刷新投票(不许使用XMLHttpRequest对象)
分析:在XHR对象没有流行之前,我们已经有“无刷新”这种效果的要求。
方法1:利用HTTP 204 状态码
利用HTTP 204 No Content状态码,当浏览器收到204时,页面不做跳转。
// html
<div>
<p>
<img width="200px" src="./wmc.jpg">
</p>
<a href="01-vote.php">投票方法1</a>
<button onclick="vote()">投票方法2</button>
<button onclick="loadCss()">投票方法3</button>
<button onclick="loadJs()">投票方法3</button>
<button onclick="ifra()">投票方法4</button>
</div>复制代码
// 01-vote.php
$cnt = file_get_contents('./res.txt');
$cnt += 1;
file_put_contents('./res.txt',$cnt);
// 利用HTTP协议的 204 特性
header('HTTP/1.1 204 No Content');复制代码
方法2:利用图片加载的特性,来完成请求
function vote() {
var wmc = document.createElement('img');
wmc.src = './01-vote.php';
}复制代码
方法3:利用css,javascript加载的特性,完成请求。
function loadCss() {
var link = document.createElement('link');
link.rel="stylesheet"; // 如果不加此属性,css文件不会加载
link.href = './01-vote.php';
link.id = 'css';
document.body.appendChild(link);
setTimeout(function(){
document.body.removeChild(document.getElementById('css'));
},300)
}
function loadJs() {
var script = document.createElement('script');
script.src = './01-vote.php';
script.id = 'js';
document.body.appendChild(script);
setTimeout(function(){
document.body.removeChild(document.getElementById('js'));
},300)
}复制代码
方法4:利用iframe的特性
function ifra() {
var iframe = document.createElement('iframe');
iframe.src = './01-vote.php';
iframe.id = 'iframe';
document.body.appendChild(iframe);
setTimeout(function(){
document.body.removeChild(document.getElementById('iframe'));
},300)
}复制代码
应用iframe无刷新注册
输入用户名,密码。点击提交。页面无刷新,显示注册成功。
// html
<div id="msg"></div>
<form action="./02-reg.php" method="post" target="regzone">
<p><label>用户名:</label><input type="text" name="username"></p>
<p><label>密码:</label><input type="password" name="password"></p>
<p><input type="submit" value="提交"></p>
</form>
<iframe width="0" height="0" name="regzone" frameborder="0"></iframe>复制代码
// 02-reg.php
<?php
// 1. 校验数据的合法性
// 2. 写入数据库等业务逻辑
// 3. 经过运算,注册成功,$res=1
$res = 1;
?>
<script>
parent.document.getElementById('msg').innerHTML = '注册成功';
</script>复制代码
现代化的AJAX
XMLHTTPRequest对象,一个专门的HTTP请求工具。
如何使用XMLHttpRequest
做AJAX
请求?
// 分析
1.如何创建该对象?
2.如何请求后台服务器资源?
3.请求的结果如何在`JS`拿到?复制代码
如何创建XHR对象
使用 new 操作符,在W3C标准下,可以通过
new XMLHttpRequest()
得到。考虑低版本的IE,可以使用new ActiveXObject('Microsoft.XMLHTTP')
得到。
function createXHR(){
return window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
}复制代码
如何利用XHR来发送请求
根据http协议,要请求需要明确这样几个因素:
1.用什么方法来请求?
GET POST PUT DELETE HEAD
2.请求哪个资源(URL)?
3.请求方式?-同步/异步
4.如何获取请求的返回数据?
答:XHR对象本身有一个属性,
responseText
就代表返回值。
5.引起的疑问?
如果是异步,下面的代码继续执行,等你的请求最终完成了。我该怎么知道这个变化呢?
答:XHR对象在请求与响应的过程中,状态不断变化(0-4)。我们可以绑定一个函数来监听状态的变化,只要状态变化就触发函数。XHR的
readyState
状态最终要变到4,当变到4时,意味着请求结束了。
6.如何绑定状态变化的回调函数?
xhr.onreadystatechange = function(){
var pg = document.getElementById('progress');
pg.innerHTML = pg.innerHTML + '状态已经变成' + this.readyState + '<br>';
}复制代码
状态值:
- 0:XHR对象刚创建成功时。(请求未初始化,在调用 open() 之前)
- 1:open成功后为1(此时已成功建立连接)(请求已提出,调用 send() 之前)
- 2:接收头信息完毕后,为数字2(请求已发送,这里通常可以从响应得到内容头部)
- 3:接收body信息后状态为3(请求处理中,响应中通常有部分数据可用,但是服务器还没有完成响应)
- 4:可以获取responseText数据。(请求已完成,可以访问服务器响应并使用它)
简单AJAX请求
// 03-vote.php
sleep(3);
if(rand(1,10) < 4) {
echo '0';
} else {
$cnt = file_get_contents('./res.txt');
$cnt += 1;
file_put_contents('./res.txt',$cnt);
echo '1';
}复制代码
重写投票方法2的vote函数:
function vote() {
// 1:制造xhr
var xhr = createXHR();
// 2: 打开连接
xhr.open('GET','./03-vote.php',true);
// 3: 发请求
xhr.send(null);
// 绑定状态变化的回调函数
xhr.onreadystatechange = function () {
if(this.readyState == 4) {
if(this.responseText == '1') {
document.getElementById('progress').innerHTML = '投票成功';
} else if(this.responseText == '0'){
document.getElementById('progress').innerHTML = '投票失败';
} else {
document.getElementById('progress').innerHTML = this.responseText;
}
}
var pg = document.getElementById('progress');
pg.innerHTML = pg.innerHTML + '状态现在变成' + this.readyState + '<br />';
}
alert('后面的代码继续执行');
}复制代码
XHR属性详解
responseText
服务器响应的主题信息,body信息responseXML
对于大量的格式化文档,可以用XML来传输或交换。由后台程序把数据封装在XML文档。js接收XML对象并解析该内容。status
是服务器返回的状态码,例如:200 success 成功,403 forbidden 禁止,404 not found 未找到,50X 系列 服务器错误。statusText
状态码对应的文字描述。readyState
XHR对象的自身状态码。onreadystatechange
事件属性,是一个函数,xhr对象的状态码发生变化时,触发该事件属性绑定的函数。
// 06-vote.php
sleep(5);
$str = 'abcdefg';
echo str_shuffle($str);复制代码
重写投票方法2的vote函数:
function vote() {
var xhr = createXHR();
xhr.open('GET','./06-vote.php',true);
xhr.send(null);
// 绑定状态变化的回调函数
xhr.onreadystatechange = function () {
if(this.readyState == 4 && this.status == 200) {
var str = '';
str = '状态码是' + this.status + '<br>';
str = str + '状态文字是' + this.statusText + '<br>';
str = str + '返回类型是:' + this.getResponseHeader('Content-Type') + '<br>';
str = str + '返回的主体长度是' + this.getResponseHeader('Content-Length') + '<br>';
str = str + '返回的主体内容是' + this.responseText + '<br><br>';
str = str + '所有头信息' + this.getAllResponseHeaders();
document.getElementById('progress').innerHTML = str;
}
}
}
/**
状态码是200
状态文字是OK
返回类型是:text/html; charset=utf-8
返回的主体长度是7
返回的主体内容是dbafgce
所有头信息
connection: Keep-Alive
content-length: 7
content-type: text/html;
charset=utf-8
date: Wed, 11 Dec 2019 13:25:06 GMT
keep-alive: timeout=5, max=98
server: Apache/2.4.9 (Win64) PHP/5.5.12
x-powered-by: PHP/5.5.12
*/复制代码
XHR方法详解
open(requestMethod,url,sync/async)
sync(同步:false) async(异步:true)send(null/params)
params的写法: k1=v1&k2=v2&kn=vn 即键值对setRequestHeader(key,value)
设置请求的头信息。abort()
中断当前的AJAX请求getResponseHeader()
获取响应的头信息。getAllResponseHeader()
获取所有的头信息。
如何POST数据
通过一个例子说明。
get方式提交数据是明文可见的,当用户提交的信息比较私密的情况下,这时我们需要使用POST的方式提交数据。
<!-- 用户注册表单 -->
<div id="regres"></div>
<form action="07-ajaxreg.php" method="post" onsubmit="return ajaxreg();">
<p>用户名:<input type="text" name="username" /></p>
<p>邮件地址:<input type="text" name="email" /></p>
<p><input type="submit" name="注册" /></p>
</form>
<script>
/*
步骤1: 打开到后台服务器连接(POST连接)
步骤2: 收集表单的数据
步骤3: 发送数据
步骤4: 监听,回调等
*/
function ajaxreg() {
// 0:制造xhr
var xhr = createXHR();
// 1: 打开POST连接
xhr.open('POST','./07-ajaxreg.php',true);
// 4. 监听回调
xhr.onreadystatechange = function() {
if(this.readyState == 4) {
alert(this.responseText);
}
}
// 2: 收集表单数据
var un = document.getElementsByName('username')[0].value;
var eml = document.getElementsByName('email')[0].value;
// 3: send
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('username='+un+'&email=' + eml);
return false;
}
</script>复制代码
print_r($_POST);复制代码
返回值类型
不考虑HTML5,严格来说,只有普通文本和XML两种类型。
作为普通文件返回类型时,又有以下几种常用的变通形式:
- 返回简短的标志字符串,如:0 1 OK
- 后台返回dad大段的HTML代码,前端直接innerHTML到页面中。
- JSON格式,再用js解析。
- 返回JSONP跨域
测试各种返回值:
书名:<input type="text" id="btitle" /><br>
简介:<input type="text" id="bintro" /><br>
<input type="button" value="测试返回XML" onclick="test1();">
<input type="button" value="测试返回html代码" onclick="test2();">
<input type="button" value="测试返回json格式" onclick="test3();">
<div id="news"></div>
<script>
function test1() {
var xhr = createXHR();
xhr.open('GET','08-returntype.php',true);
xhr.onreadystatechange = function() {
if(this.readyState == 4) {
var xmldom = this.responseXML;
var chs = xmldom.getElementsByTagName('book')[0];
document.getElementById('btitle').value = chs.firstChild.firstChild.wholeText;
document.getElementById('bintro').value = chs.lastChild.firstChild.wholeText;
}
}
xhr.send(null);
}
function test2() {
var xhr = createXHR();
xhr.open('GET','08-returnhtml.php',true);
xhr.onreadystatechange = function() {
if(this.readyState == 4) {
document.getElementById('news').innerHTML = this.responseText;
}
}
xhr.send(null);
}
function test3() {
var xhr = createXHR();
xhr.open('GET','08-returnjson.php',true);
xhr.onreadystatechange = function() {
if(this.readyState == 4) {
var book = eval('('+this.responseText+')');
document.getElementById('btitle').value = book.title;
document.getElementById('bintro').value = book.intro;
}
}
xhr.send(null);
}
</script>复制代码
// 08-returntype.php
<?php
header('Content-Type: text/xml');
?>
<?xml version="1.0" encoding="utf-8"?>
<bookstore><book bid="b008"><title>天龙八部</title><intro>人生太苦了</intro></book></bookstore>
复制代码
// 08-returnhtml.php
// 从数据库取出N条数据
foreach(array('新闻1','新闻2','新闻3') as $v) {
echo '<li>',$v,'</li>';
}
复制代码
// 08-returnjson.php
// 从数据库取出N条数据
$book = array('title'=>'天龙八部','intro'=>'人生八苦');
echo json_encode($book);
复制代码
跨域JSONP
通过js创建script标签,来实现跨域。
<input type="text" name="keyword" /><br />
<input type="button" value="搜索" onclick="cors();" />
<div id="szone"></div>
<script>
function cors() {
var kw = document.getElementsByName('keyword')[0].value;
var url = 'https://www.baidu.com/sugrec?ie=utf-8&json=1&prod=pc&from=pc_web&wd='
+ encodeURI(kw) + '&req=2&csor=2&cb=callback';
var scr = document.createElement('script');
scr.setAttribute('type','text/javascript');
scr.setAttribute('src',url);
document.getElementsByTagName('head')[0].appendChild(scr);
}
function callback(res) {
var results = res.g;
var szone = document.getElementById('szone');
var str = '';
for(var i in results) {
str += '<p>'+ results[i].q + '<p/>';
}
szone.innerHTML = str;
}
</script>复制代码