ajax详细介绍

kkcode
kkcode
2018-05-20阅读 1502

远古时代的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>

参考

评论数量:0