Ajax
什么是ajax
Ajax: asynchronous javascript and xml (异步js和xml)
其是可以与服务器进行(异步/同步)交互的技术之一。
ajax的语言载体是javascript。
最大特点:页面不刷新
ajax出现的历史
1999年,微软公司发布IE5浏览器的时候嵌入的一种技术。起初名字是XMLHttp。
直到2005年,google公司发布了一个邮箱产品gmail,内部有使用ajax技术,该事情引起人们对ajax的注意,也使得一蹶不振的javascript语言从此被人们重视起来。
ajax技术是许多旧技术的集合
xhtml、css、javascript、xml、xmlhttprequest对象(ajax对象)
其中XMLHttpRuquest是ajax的官方的名称。
ajax使用
创建ajax对象
主流(火狐、google、苹果safari、opera)浏览器方式
包括IE7以上版本的浏览器
var xhr = new XMLHttpRequest();
IE(6/7/8)方式
var xhr = new ActiveXObject(“Microsoft.XMLHTTP”); //最原始方式
var xhr = new ActiveXObject("Msxml2.XMLHTTP"); //升级
var xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0"); //升级
var xhr = new ActiveXObject("Msxml2.XMLHTTP.5.0"); //升级
var xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0"); //最高版本方式
<script type='text/javascript'>
//创建ajax对象
if(typeof XMLHttpRequest != 'undefined'){
//主流方式
var xhr = new XMLHttpRequest();
}else{
//IE(6/7/8)方式
var xhr = new ActiveXObject("Microsoft.XMLHTTP"); //最原始方式
var xhr = new ActiveXObject("Msxml2.XMLHTTP"); //升级
var xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0"); //升级
var xhr = new ActiveXObject("Msxml2.XMLHTTP.5.0"); //升级
var xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0"); //最高版本方式
}
alert(xhr);
</script>
发起对服务器的请求
<script type='text/javascript'>
//ajax 发起请求
//1、创建对象
var xhr = new XMLHttpRequest();
//2、创建一个新的http请求(打开浏览器,输入请求地址)
//xhr.open(请求方式get/post等等,请求地址[,异步同步请求]);
xhr.open('get','../1.php');
//3、发送请求
//xhr.send(post请求数据 / get请求设置null);
xhr.send(null);
</script>
接收服务器返回信息
ajax可以接收什么信息?
答:浏览器可以接收的信息ajax都可以接收,例如字符串、html标签、css样式内容、xml内容、json内容等等。
<html>
<head>
<meta charset='utf-8' />
<script type='text/javascript'>
function f1(){
var xhr = new XMLHttpRequest();
//设置事件onreadystatechange 感知ajax状态变化
xhr.onreadystatechange = function(){
//readyState 变量表示ajax对象状态,其值见下文
console.log(xhr.readyState);
if(xhr.readyState==4)
//xhr.responseText 可返回页面echo出的内容
alert(xhr.responseText);
}
xhr.open('get','../1.php');
xhr.send(null);
}
</script>
</head>
<body>
<input type='button' value='点击' onclick='f1()'>
</body>
</html>
readyState 为只读变量,状态用长度为4的整型表示,定义如下:
值 | 代表意义 |
---|---|
0 (未初始化) | 对象已建立,但是尚未初始化(尚未调用open方法) |
1 (初始化) | 对象已建立,尚未调用send方法 |
2 (发送数据) | send方法已调用,但是当前的状态及http头未知 |
3 (数据传送中) | 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误 |
4 (完成) | 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据 |
常用属性
属性 | 代表意义 |
---|---|
onreadystatechange* | 指定当readyState属性改变时的事件处理句柄。只写 |
readyState | 返回当前请求的状态,只读. |
responseBody | 将回应信息正文以unsigned byte数组形式返回.只读 |
responseStream | 以Ado Stream对象的形式返回响应信息。只读 |
responseText | 将响应信息作为字符串返回.只读 |
responseXML | 将响应信息格式化为Xml Document对象并返回,只读 |
status | 返回当前请求的http状态码.只读 |
statusText | 返回当前请求的响应行状态,只读 |
常用方法
方法 | 代表意义 |
---|---|
abort | 取消当前请求 |
getAllResponseHeaders | 获取响应的所有http头 |
getResponseHeader | 从响应信息中获取指定的http头 |
open | 创建一个新的http请求,并指定此请求的方法、URL以及验证信息(用户名/密码) |
send | 发送请求到http服务器并接收回应 |
setRequestHeader | 单独指定请求的某个http头 |
get和post方式的ajax请求
ajax对象.open(get/post, 请求地址);
两者的不同
- 给服务器传递数据量,get最多是2k
post原则没有限制,php.ini对其限制为8M - 安全方面,post传递数据较安全
传递数据的形式不一样
get方式在url地址后边以请求字符串形式传递参数
http://网址/index.php?name=tom&age=23&addr=beijingpost方式是把form表单的数据给请求出来以xml形式传递给服务器
ajax之get方式请求
- 在url地址后边以请求字符串(传递的get参数信息)形式传递数据。
- 对中文、=、&等特殊符号处理
=、&符号在浏览器里边会与请求字符串的关键符号有混淆,避免歧义产生需要对其进行编码.
在浏览器的地址栏里边传递一些特殊符号信息,会被误解,例如 & = 空格 中文。
在php里边可以函数函数 urlencode()/urldecode() 对特殊符号进行编码、反编码处理
(url_encode()可以把中文转变为浏览器可以识别的信息。转变之后的信息具体为%号后接两个十六进制数)
在javascript里边可以通过 encodeURIComponent () 对特殊符号等信息进行编码。
经过以上 加粗 函数编码的内容在服务器端可以正常接收,不需要反编码。
ajax之post方式请求
- 给服务器传递数据需要调用send(请求字符串数据)方法
- 调用方法setRequestHeader()把传递的数据组织为xml格式(模仿form表单给服务器传递数据)
- 传递的中文信息无需编码,特殊符号像 &、=等 需要编码
- 该方式请求的同时也可以传递get参数信息,同样使用$_GET接收该信息
<html>
<head>
<meta charset='utf-8' />
<script type='text/javascript'>
function f1(){
//ajax 负责抓取用户名信息,传递给服务器进行校验
//获取用户名信息
var un = document.getElementsByTagName('input')[0].value;
un = encodeURIComponent(un);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState==4)
alert(xhr.responseText);
}
xhr.open('post','../1.php');
//post模仿form表单把数据传递给服务器
//form表单把数据组织为“xml格式”传递给服务器
//把传递的数据组织为请求字符串
//以下方法设置header头信息,作用把传递的数据组织为xml格式
//(要在open()方法执行之后设置)
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
var info = 'name='+un+'&age=20';
xhr.send(info);
}
</script>
</head>
<body>
<input type='text' value='' name='username'>
<input type='button' value='提交' onclick='f1()'>
</body>
</html>
同步、异步
ajax是可以与服务器进行(异步或同步)交互的技术之一。
异步:同一个时间点允许执行多个进程。
同步:同一个时间点只允许执行一个进程。
ajax对象.open(请求方式,请求地址,同步false/[异步true]);
<script type='text/javascript'>
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
document.body.innerHTML += xhr.responseText;
//alert(xhr.responseText);
}
}
//true 异步 false 同步
xhr.open('get','../1.php',true);
//xhr.open('get','../1.php',false);
xhr.send(null);
</script>
什么时候使用同步请求
ajax绝大多数情况下进行异步请求,但是有的时候也要使用“同步请求”(其不能被取代)。例如页面有两部分内容,一前一后,ajax请求和正常的html内容输出,如果html的输出内容包括ajax请求的内容,就需要使得ajax请求完成了再进行html内容的输出,这样就要设置两者一前一后调用(而非同时调用),此时要使用同步请求。
ajax无刷新分页效果
http://网址/data.php?page=1
http://网址/data.php?page=2
http://网址/data.php?page=3
.....
传统分页效果,获得每页信息的时候全部页面都需要刷新。
无刷新分页的必要性
如果我们通过“传统方式”实现上图的商品评论分页效果,每次分页的时候就会使得头部、左侧、底部等已经显示的信息重新从服务器获得出来,这样对带宽、服务器资源、用户等待时间都有额外的损耗。如果使用ajax无刷新分页,每次就只从服务器获得“商品评论区域”信息即可,对各方面资源的使用就有相应节省。因此ajax无刷新分页效果有其存在必要性。
具体实现
记录总条数
每页显示条数
总页数:向上取整(总条数/每页显示条数)
limit 偏移量((当前页码-1)*每页条数),长度;
http://网址/data.php?page=1 (limit 0,7)
http://网址/data.php?page=2 (limit 7,7)
http://网址/data.php?page=3 (limit 14,7)
ajax对象.open(‘get’,地址http://网址/data.php?page=2);
利用ajax无刷新方式获得第2页信息
制作传统分页效果
page.class.php
<?php
class Page {
private $total; //数据表中总记录数
private $listRows; //每页显示行数
private $limit;
private $uri;
private $pageNum; //页数
private $config=array('header'=>"个记录", "prev"=>"上一页", "next"=>"下一页", "first"=>"首 页", "last"=>"尾 页");
private $listNum=8;
/*
* $total
* $listRows
*/
public function __construct($total, $listRows=10, $pa=""){
$this->total=$total;
$this->listRows=$listRows;
$this->uri=$this->getUri($pa);
$this->page=!empty($_GET["page"]) ? $_GET["page"] : 1;
$this->pageNum=ceil($this->total/$this->listRows);
$this->limit=$this->setLimit();
}
private function setLimit(){
return "Limit ".($this->page-1)*$this->listRows.", {$this->listRows}";
}
private function getUri($pa){
$url=$_SERVER["REQUEST_URI"].(strpos($_SERVER["REQUEST_URI"], '?')?'':"?").$pa;
$parse=parse_url($url);
if(isset($parse["query"])){
parse_str($parse['query'],$params);
unset($params["page"]);
$url=$parse['path'].'?'.http_build_query($params);
}
return $url;
}
function __get($args){
if($args=="limit")
return $this->limit;
else
return null;
}
private function start(){
if($this->total==0)
return 0;
else
return ($this->page-1)*$this->listRows+1;
}
private function end(){
return min($this->page*$this->listRows,$this->total);
}
private function first(){
$html = "";
if($this->page==1)
$html.='';
else
$html.=" <a href='{$this->uri}&page=1'>{$this->config["first"]}</a> ";
return $html;
}
private function prev(){
$html = "";
if($this->page==1)
$html.='';
else
$html.=" <a href='{$this->uri}&page=".($this->page-1)."'>{$this->config["prev"]}</a> ";
return $html;
}
private function pageList(){
$linkPage="";
$inum=floor($this->listNum/2);
for($i=$inum; $i>=1; $i--){
$page=$this->page-$i;
if($page<1)
continue;
$linkPage.=" <a href='{$this->uri}&page={$page}'>{$page}</a> ";
}
$linkPage.=" {$this->page} ";
for($i=1; $i<=$inum; $i++){
$page=$this->page+$i;
if($page<=$this->pageNum)
$linkPage.=" <a href='{$this->uri}&page={$page}'>{$page}</a> ";
else
break;
}
return $linkPage;
}
private function next(){
$html = "";
if($this->page==$this->pageNum)
$html.='';
else
$html.=" <a href='{$this->uri}&page=".($this->page+1)."'>{$this->config["next"]}</a> ";
return $html;
}
private function last(){
$html = "";
if($this->page==$this->pageNum)
$html.='';
else
$html.=" <a href='{$this->uri}&page=".($this->pageNum)."'>{$this->config["last"]}</a> ";
return $html;
}
private function goPage(){
return ' <input type="text" onkeydown="javascript:if(event.keyCode==13){var page=(this.value>'.$this->pageNum.')?'.$this->pageNum.':this.value;location=\''.$this->uri.'&page=\'+page+\'\'}" value="'.$this->page.'" style="width:25px"><input type="button" value="GO" onclick="javascript:var page=(this.previousSibling.value>'.$this->pageNum.')?'.$this->pageNum.':this.previousSibling.value;location=\''.$this->uri.'&page=\'+page+\'\'"> ';
}
function fpage($display=array(0,1,2,3,4,5,6,7,8)){
$html[0]=" 共有<b>{$this->total}</b>{$this->config["header"]} ";
$html[1]=" 每页显示<b>".($this->end()-$this->start()+1)."</b>条,本页<b>{$this->start()}-{$this->end()}</b>条 ";
$html[2]=" <b>{$this->page}/{$this->pageNum}</b>页 ";
$html[3]=$this->first();
$html[4]=$this->prev();
$html[5]=$this->pageList();
$html[6]=$this->next();
$html[7]=$this->last();
$html[8]=$this->goPage();
$fpage='';
foreach($display as $index){
$fpage.=$html[$index];
}
return $fpage;
}
}
<?php
//传统分页效果实现
//连接数据库,获得数据,做分页显示
header("content-type:text/html;charset=utf-8");
$link = mysql_connect('localhost','root','123456');
mysql_select_db('shop', $link);
mysql_query('set names utf8');
echo <<<eof
<style type="text/css">
table {width:700px; border:1px solid black; margin:auto; border-collapse:collapse;}
td {border:1px solid black; }
</style>
<table>
<tr style='font-weight:bold'><td>序号</td><td>名称</td><td>价格</td><td>数量</td><td>重量</td></tr>
eof;
//① 引入分页类
include "./page.class.php";
//② 获得总条数、每页显示条数
$sql = "select * from sw_goods";
$qry = mysql_query($sql);
$total = mysql_num_rows($qry); //总条数
$per = 7;//每页条数
//③ 实例化分页类对象
$page = new Page($total, $per);
//④ 设置sql语句获得每页信息
//$page->limit:分页类会根据当前页码参数自动把 "limit 偏移量,长度" 信息给拼装好
$sql3 = "select * from sw_goods order by goods_id ".$page->limit;
$qry3 = mysql_query($sql3);
//⑤ 获得页码列表信息
$page_list = $page -> fpage(array(3,4,5,6,7,8));
$page_num = isset($_GET['page'])?$_GET['page']:1;
$num = ($page_num-1)*$per+1;
while($rst3 = mysql_fetch_assoc($qry3)){
printf("<tr>");
printf("<td>%d</td>",$num);
printf("<td>%s</td>",$rst3['goods_name']);
printf("<td>%s</td>",$rst3['goods_price']);
printf("<td>%d</td>",$rst3['goods_number']);
printf("<td>%d</td>",$rst3['goods_weight']);
printf("</tr>");
$num++;
}
printf("<tr><td colspan='5'>%s</td></tr>",$page_list);
echo "</table>";
制作ajax无刷新分页效果
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>新建网页</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<script type="text/javascript">
//函数封装,实现ajax获取分页信息
function showpage(url){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
document.getElementById('result').innerHTML = xhr.responseText;
}
}
xhr.open('get',url);
xhr.send(null);
}
window.onload = function(){
showpage('./data.php');
}
</script>
<style type="text/css">
h2,div {width:700px; margin:auto;}
h2 {text-align:center;}
</style>
</head>
<body>
<h2>ajax无刷新分页</h2>
<div id="result"></div>
</body>
</html>
<script type="text/javascript">
<!--
document.write(new Date()+"<br />");
document.write(new Date()+"<br />");
document.write(new Date()+"<br />");
document.write(new Date()+"<br />");
//-->
</script>
ajax对xml信息的接收和处理
ajax负责请求xml和接收xml信息,dom负责处理xml信息
dom:
php里边,dom是php与xml(html)之间的沟通桥梁
javascript里边,dom是javascript与html(xml)之间沟通桥梁
08.xml
<?xml version="1.0" encoding="utf-8" ?>
<students>
<student>
<name>刘飞</name>
<age>20</age>
<addr>辽宁</addr>
</student>
<student>
<name>苏建</name>
<age>21</age>
<addr>河北</addr>
</student>
<student>
<name>王阳</name>
<age>18</age>
<addr>山东</addr>
</student>
</students>
<script type="text/javascript">
function f1(){
//ajax请求xml信息回来
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
//alert(xhr.responseText); //以字符串格式返回xml信息
//alert(xhr.responseXML); //[object XMLDocument]以xmldocument对象格式返回xml信息
var xmldom = xhr.responseXML;
//console.log(xmldom.firstChild);//<students>
//console.log(xmldom.firstChild.childNodes);//NodeList[<TextNode textContent="\n ">, student, <TextNode textContent="\n ">, student, <TextNode textContent="\n ">, student, <TextNode textContent="\n">]
//文档对象.getElementsByTagName(tag名称);
//元素节点.getElementsByTagName(tag名称);
var std = xmldom.getElementsByTagName('student');
//console.log(std);//HTMLCollection[student, student, student]
//console.log(std[0]);//<student>元素节点对象
//for(var k in std[0]){
// console.log(k);
//}
var s = "";
for(var i=0; i<std.length; i++){
var nm = std[i].getElementsByTagName('name')[0].innerHTML;
var age = std[i].getElementsByTagName('age')[0].firstChild.wholeText;
var addr = std[i].getElementsByTagName('addr')[0].innerHTML;
s += "名称:"+nm+"--年龄:"+age+"--地址:"+addr+"<br />";
}
document.body.innerHTML += s;
}
}
xhr.open('get','./08.xml');
xhr.send(null);
}
</script>
ajax对缓存的处理
缓存:
一次请求需要从服务器获得许多 css、img、js 等相关的文件,如果每次请求都把相关的资源文件加载一次,对 带宽、服务器资源、用户等待时间 都有严重的损耗,浏览器有做优化处理,其把css、img、js在第一次请求成功后就在本地保留一个缓存备份,后续的每次请求就在本身获得相关的缓存资源文件及可以了,可以明显地加快用户的访问速度。
css、img、js等文件可以缓存,但是动态程序文件例如php文件不能缓存,即时缓存我们也不要其缓存效果。
缓存解决:
① 确保每次的请求地址信息是唯一的
② 在php代码里边设置header头,禁止浏览器缓存当前页面
09-cache.html
<script type="text/javascript">
//ajax发起请求
function f1(){
//创建ajax对象,对象调用成员实现对服务器的请求
//① 创建对象
var xhr = new XMLHttpRequest();
//② 创建一个新的http请求(打开浏览器,输入请求地址)
//xhr.open(请求方式get/post,请求地址[,异步同步请求]);
//xhr.open("get",'./09.php?'+Math.random());//设置随机数,避免缓存效果
xhr.open("get",'./09.php');
//③ 发送请求
//xhr.send(post请求数据 / get请求设置null);
xhr.send(null);
}
</script>
09.php
<?php
//以下三行,禁止浏览器缓存页面
header("Cache-Control:no-cache");
header("Pragma:no-cache");
header("Expires:-1");
$fp = fopen('./09.txt','a'); //打开文件
fwrite($fp,'computer\n'); //给文件写内容
fclose($fp);//关闭文件
echo "haha";
thinkphp框架使用ajax
ajax对象.open(‘get/post’, 绝对路径地址);
ajax对象.open(‘get/post’, /shop/index.php/Home/User/checkname);