ajax 简介
业务:
做一个在线投票,给歌手投票。
要求:无刷新,并且不允许使用XMLHttpRequest对象.
分析:在XHR对象,没有流行之前,已经有了“无刷新”这种效果的方法.
从http角度看,可以利用204 No content 状态码的特性
可以使用
iframe
利用图片加载的特性
可以使用
script
<script src="" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href=""/>
<a href=""></a>
<iframe src="" width="" height=""></iframe>
<img src=""/>
无刷新只是表面现象,本质上,是需要发送一个请求,把数据送到后台.
<?php
if ( !file_exists('./res.txt') ) {
fopen('./res.txt', 'wbr');
}
$cnt = file_get_contents('./res.txt');
$cnt += 1;
file_put_contents('./res.txt', $cnt);
// 利用HTTP协议的204特性
header('HTTP/1.1 204 No Conent'); // 没有内容,浏览器不理会当前文件,这次请求之后的一系列的跳转就当作没有发生.
?>
业务需求:
AJAX注册,提交表单,要求页面无刷新.
利用iframe
特性
iframe
嵌入在当前页面。
post提交到当前页面的iframe
中,达到ajax效果
。
<form action="reg.php" method="post" target="regzone">
<p>
用户名:<input type="text" name="username" />
</p>
<p>
密码:<input type="password" name="pass" />
</p>
<input type="submit" value="注册"/>
<iframe style="display: none;" width="" height="" name="regzone"></iframe>
</form>
总结:
在不使用XMLHttpRequest
对象的情况下,依然可以用js来实现对后台服务器的请求,同时不带来页面刷新或者跳转。
所谓AJAX:
即是指:页面不刷新的情况下,利用XMLHttpRequest
对象发送HTTP请求.或者JavaScript的网络化.
AJAX文件上传实现原理(HTTP协议+JS引擎)的角度:
分析:从HTTP协议的角度来看,则要把文件的内容发送到服务器.如果可以,说明XMLHttpRequest对象在POST数据时,把文件的内容也发送到服务器,---> XHR对象获取了你要上传的文件的内容. ---> JavaScript读取了本地的文件内容. ---> 处于安全原因,JavaScript是不能够读取到本地文件内容.
因此:AJAX原理上是无法实现的.
利用伪AJAX方式来实现.
iframe
来实现.用flash实现。如:
swfuploaded
插件HTML5实现。(HTML5增加了文件读取API)
AJAX
核心:XMLHttpRequest
对象.
XML对象一个专门的HTTP请求的工具.
如何使用XMLHttpRequrest
对象做AJAX请求?
分析:
如何实例化该对象.
如何请求后台资源.
请求结果如何得到(双向通信).
创建XML对象.
new XMLHttpRequest();
如何通过XHR发送请求?
分析HTTP协议,要请求需要明确因素?
根据请求行:
-
用什么方法来请求.
GET,POST,PUT,DELETE,HEAD
请求那个资源(URL)
-
同步方式
同步,异步
获取返回信息
XHR对象本身有一些属性,responseText
,表示返回值.
xhr.responseText
使用异步,如何知道请求完成.
XHR对象在请求与响应的过程中,状态会不断变化(0-4)xhr.readyState
,逐步变化. 可以绑定一个函数,监听状态变化,只要状态发生变化,就触发函数xhr.onreadystatechange
返回值类型
不考虑HTML5最新的标准,返回值:普通文本
/xml文档
.二种返回形式
XML文档
function createXHR() {
var xhr = null;
if ( window.ActiveXObject ) {
xhr = new window.ActiveXObject();
} else if ( XMLHttpRequest ) {
xhr = new XMLHttpRequest('Microsoft.XMLHTTP');
}
return xhr;
}
// xml
function test1() {
var xhr = createXHR();
xhr.open('GET', './returntype.php', true);
xhr.onreadystatechange = function () {
if ( this.readyState == 4 ) {
var xmldom = this.responseXML;
console.log( xmldom );
}
}
xhr.send(null);
}
普通文本
普通文本变通形式:
后台返回大段的html代码,直接innerHTML到前台页面.
json格式的普通文本.
返回简短的标志字符串 如: 0, 1, ok.
function createXHR() {
var xhr = null;
if ( window.ActiveXObject ) {
xhr = new window.ActiveXObject();
} else if ( XMLHttpRequest ) {
xhr = new XMLHttpRequest('Microsoft.XMLHTTP');
}
return xhr;
}
// 返回普通文本的html代码字符串
function test2() {
var xhr = createXHR();
xhr.open('GET', './returnhtml.php', true);
xhr.onreadystatechange = function () {
if ( this.readyState == 4 ) {
console.log( this.responseText );
}
}
xhr.send(null);
}
// json格式字符串对象
function test3() {
var xhr = createXHR();
xhr.open('GET', './returnjson.php', true);
xhr.onreadystatechange = function () {
if ( this.readyState == 4 ) {
console.log( this.responseText );
}
}
xhr.send(null);
}
jsonp格式
jsonp是跨域解决的一种方式.
<script type="text/javascript">
var oSc = document.createElement('script');
// (调用函数)
oSc.src = 'http://?callback=pink';
oSc.setAttribute('type', 'text/javascript');
oSc.appendChild('body');
// 返回的数据 (定义函数)
function pink( data ) {
};
</script>
异步原理
readyState
状态值:
通过插队机制
,把回调函数插入到当前已经执行代码的前方。
HTML5与AJAX
iframe
扑捉表单提交动作(onsubmit)
创建一个iframe
把表单的target修改 指向 该 iframe
销毁iframe
$('form').submit(function () {
var upName = 'up' + Math.random();
$('<iframe>').attr('name', upName).css('display', 'none').appendTo($('body'));
$(this).attr('target', upName);
// loading
$('#msg').html('<img src="./load.gif" />');
});
$error = $_FILES['pic']['error'] == 0 ? 'success' : 'fail';
sleep(2);
if ( $error == 0 ) {
echo '<script>
parent.document.getElementById("msg").innerHTML = "'. $error .'"
</script>';
} else {
echo '上传失败';
}
FormData
进度条: 总大小, 已上传大小
解决:在HTML5中,有一个"上传过程"的事件(onprogress),事件中,可以读取到当前两个信息.
思路:在上传过程中,不断触发函数,读取(已上传/总大小),更新页面数据。
FormData使用注意
每个表单域必须有name属性
不能设置
setRequestHeaer
头特殊符号无须编码
在form标签里无须设置
enctype='multipart/form-data'
属性(即使有上传文件域也不需要设置)
(无刷新上传附件,FormData可以收集上的文件域信息)
AJAX对象-> upload -> onprogress
AJAX对象有成员属性upload
,是一个对象,该对象有一个onprogress
属性,该属性是一个时间,该事件每间隔0.1秒执行一次,执行过程中会知道当前的附件上传情况。(例如:文件上传的总大小,目前已经上传大小等信息)
/**
* file文件上传
*/
function selfile() {
// 创建FromData对象
var fd = new FormData();
// 获取文件对象
var pic = document.getElementsByTagName('input')[0].files[0];
// 把获取的文件对象追加到表单数据中.
fd.append('pic', pic);
// fd.pic = pic;
// AJAX
var xhr = new XMLHttpRequest();
xhr.open('POST', 'upfile.php', true);
xhr.onreadystatechange = function () {
if ( xhr.readyState == 4 ) {
document.getElementById("debug").innerHTML = xhr.responseText;
}
}
xhr.upload.onprogress = function ( ev ) {
// 长度是否可以计算. (区分:分块上传)
if ( ev.lengthComputable ) {
// 当前已经上传多少/总共多少
var percent = 100 * ev.loaded / ev.total;
document.getElementById('debug').innerHTML = '已经上传:' + percent.toFixed(2);
}
}
xhr.send(fd);
}
大文件切割上传
while循环实现文件上传
/**
* 使用的API
* file --> Blob
* Blob有slice, 可以截取二进制对象的一部分.
*/
/**
* 思路:
* 截取10M,上传
* 判断文件是否截取完毕
*
* while( 存在数据 ) { // 截取, 上传 }
*/
/**
* 上传文件
*/
function sendFile() {
const LENGTH = 10 * 1024 * 1024; // 一次性截取长度
var start = 0; // 从哪里开始截取
var end = start + LENGTH // 到哪边截至
var blob = new Blob();
var fd = null;
// XHR对象
var xhr = null;
// 获取总的文件大小
var pic = document.getElementById("pic").files[0];
var totalSize = pic.size;
var percent = 0;
while ( start < totalSize ) {
// 截取文件
blob = pic.slice(start, end);
fd = new FormData();
// fd.append('part', blob);
fd.part = blob;
// xml对象
xhr = new XMLHttpRequest();
xhr.open('POST', 'sliceup.php', true);
xhr.upload.onprogress = function ( ev ) {
}
// 发送请求
xhr.send(fd);
start = end;
end = start + LENGTH;
percent += 100 * end / totalSize;
if ( percent > 100 ) {
percent = 100;
}
document.getElementById("msg").style.width = percent + '%';
}
}
定时器实现切割上传
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#progress {
margin-top: 20px;
width: 500px;
height: 25px;
border: 1px solid greenyellow;
}
#msg {
width: 0;
height: 25px;
background: greenyellow;
}
</style>
</head>
<body>
<input type="file" name="pic" id="pic" /><br /><br />
<button onclick="file()">大文件切割上传</button>
<div id="progress">
<div id="msg"></div>
</div>
<script type="text/javascript">
/**
* 使用的API
* file --> Blob
* Blob有slice, 可以截取二进制对象的一部分.
*/
/**
* 思路:
* 截取10M,上传
* 判断文件是否截取完毕
*/
var xhr = new XMLHttpRequest();
var timer = null;
/**
* 上传文件
*/
function file() {
timer = setInterval(sendFile, 1000);
}
// 每个一秒执行产生的问题
// 在一秒内,没有上传完成
var sendFile = (function () {
const LENGTH = 10 * 1024 * 1024; // 一次性截取长度
var start = 0; // 从哪里开始截取
var end = start + LENGTH // 到哪边截至
var sending = true; // 上一块是否发送完毕
var blob = null;
var fd = null;
// 百分比
var percent = 0;
return function () {
if (sending == true) {
return false;
}
var file = document.getElementById("pic").files[0];
if ( start > file.size ) {
clearInterval(timer);
return false;
}
blob = file.slice(start, end);
fd = new FormData();
fd.append('part', blob);
// 上传
up(fd);
start = end;
end = start + LENGTH;
sending = false;
// 进度条
percent = 100 * end / file.size;
if ( percent > 100 ) {
percent = 100;
}
document.getElementById("msg").style.width = percent + '%';
}
})();
/**
* 上传文件
* @param {} fd
*/
function up( fd ) {
xhr.open('POST', 'sliceup.php', true);
xhr.send(fd);
}
</script>
</body>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。