代码位置:全栈教程/04_JS/JS核心第10Ajax第1天/代码/2018-09-13
二、今日目标
- 1、知道Ajax能够做什么
- 2、理解Ajax的工作原理
- 3、能够创建兼容各个浏览器的Ajax对象
- 4、能够通过get和post方式发送Ajax请求
- 5、能够用代码写出一次Ajax请求的全部过程
- 6、能够解决IE缓存
- 7、能够理解同步和异步请求的区别
- 8、知道什么是JSON以及它用什么作用
- 9、能够将JSON数据和PHP数据相互转化
- 10、能够将JSON数据和JS数据相互转化
- 11、Ajax请求能够处理服务器返回的JSON格式的数据
三、概述
手册位置:W3C手册 — 上面的JavaScript — 左侧的Ajax
1、Ajax历史
1999年,微软在IE5上使用,但是没有被认知。
2005年,谷歌的使用(地图、gmail),使得ajax被全世界所认识,并广泛使用。
2、Ajax是什么
Ajax中的第一个A是Asynchronous [eɪˈsɪŋkrənəs]
(异步)JavaScript and XML的缩写。可以看出它不是一种技术,而是多种技术的综合体。
其中有JavaScript、有xml、有json、有html、有css、有dom、有XMLHttpRequest对象等等。
XMLHttpRequest对象,也叫做Ajax对象,浏览器中自带的对象。
Ajax的工作也是基于http协议的。
3、Ajax能做什么
①、提高用户体验。
②、表单时时验证
③、百度地图、谷歌地图
④、网页版的聊天室
⑤、无刷新的分页
五、XMLHttpRequest对象介绍
1、创建xhr对象(ajax对象)
所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。
var xhr = new XMLHttpRequest(); //IE6+
//var xhr = new ActiveXObject('Microsoft.XMLHTTP'); //ie5/IE6
console.log(xhr);
2、主要的成员属性:
readyState:表示xhr工作进行到何种状态
onreadystatechange:事件,表示readyState改变的时候触发的事件
status:http状态码
responseText:用来接收返回的文本类型的数据
responseXML:用来接收返回的是XML格式的数据
3、主要的方法:
open():设置(定义)一个请求
send():发送设置好的请求
setRequestHeader():设置ajax请求头信息
六、使用Ajax的步骤
完成验证用户名案例,要求用户名唯一,就是不能有重复。
页面中有一个文本框,当失去焦点的时候,验证输出的内容是否已经存在。
1、创建所需文件
创建03chkusername.html:
<input type="text" id="username" /> <span id="msg"></span>
创建03chkusername.php
//工作是:验证提交用户输入的用户名是否已经被注册
//为了简化,模拟用户'zhangsan'、'lisi'、‘wangwu’ 已经被注册,其他用户名都可用
$arr = ['zhangsan','lisi', 'wangwu', 'aaa', 'bbb','ccc','ddd','fff', 'ggg'];
2、当input失去焦点,准备发送
因为用get方式请求,所以参数直接写到url上即可。服务器端获取地址栏的参数,同样使用$_GET来获取。
3、发送请求
调用Ajax对象的send方法发送请求到服务器。
4、服务器接收数据并判断
判断完成,将判断的结果返回给浏览器。echo出来的东西就是返回给浏览器的内容。
测试:
5、接收服务器返回的数据,并处理
经过测试,发现并没有成功接收到服务器返回的数据。通过console.log(result);查看到的结果什么都么有。
6、监听Ajax执行状态
发送请求完毕,不应该马上就接收服务器返回的数据,应该判断一下Ajax进行到哪一步了。如果说进行到最后一步了,即服务器返回数据完毕,这个时候才应该获取服务器返回的数据。
Ajax对象中用onreadystatechange属性(事件),来监听(检测)Ajax执行到哪一步了。
Ajax对象中用readyState属性来表示Ajax的状态,具体是readyState属性值如下:
源代码:
03chkusername.html
<input type="text" id="username" /> <span id="msg"></span>
<script>
//当input失去焦点的时候,发送请求
document.getElementById('username').onblur = function(){
//第一步:创建Ajax对象
var xhr = new XMLHttpRequest();
//第二步:准备工作
var uname = this.value; //要发送给服务器的用户名
//xhr.open(请求方式, 请求的地址, 同步或异步); //该方法用于发送请求前的准备工作
xhr.open('get', '03chkusername.php?u=' + uname, true); //true表示异步,默认也是true
//第三步:发送请求到服务器
xhr.send(); //send的参数表示post请求的参数,因为我们用的是get请求,所以参数不用填
//当xhr执行的时候,如果状态发生变化,就会触发事件
xhr.onreadystatechange = function(){
//readyState可能是变化有:0~1/1~2/2~3/3~4
if(xhr.readyState == 4){
//表示服务器完全返回了数据,这时才应该接收数据并处理
//第四步:接收服务器返回的数据,并处理
var result = xhr.responseText; //用responseText来接收服务器返回的文本类型的信息
console.log(result); //输出结果,什么都没有,即不是1,也不是0
if(result == 1){
document.getElementById('msg').innerHTML = '<font color="red">sorry,用户名已存在</font>';
}else if(result == 0){
document.getElementById('msg').innerHTML = '<font color="green">恭喜,用户名可用</font>';
}
}
};
};
</script>
03chkusername.php
//header("Cache-Control:no-cache");
//header("Pragma:no-cache");
//header("Expires:-1");
//工作是:验证提交用户输入的用户名是否已经被注册
//为了简化,模拟用户'zhangsan'、'lisi'、‘wangwu’ 已经被注册,其他用户名都可用
$arr = ['zhangsan','lisi', 'wangwu', 'aaa', 'bbb','ccc','ddd','fff', 'ggg'];
//接收发送过来的数据,并判断
$u = $_GET['u'];
//判断
if(in_array($u, $arr)){
//说明用户名已经存在
echo 1;
}else{
//说明用户名可用
echo 0;
}
7、使用Ajax步骤总结
七、细节问题
1、编码字符
为什么要编码:
解决的办法就是对用户输入的内容进行编码。
encodeURI() — 不能对“:/=&”进行编码,能对汉字进行编码
encodeURIComponent() — 能对“:/=&”进行编码,也能对汉字进行编码
一般情况下,JS编码后发送到服务器,PHP会自动解码,如果没有自动解码,用PHP的函数urldecode来解码。
2、缓存处理
什么是Ajax缓存原理?
Ajax在发送的数据成功后,会把请求的URL和返回的响应结果保存在浏览器缓存内,当下一次调用Ajax发送相同的请求时,它会直接从缓存中把数据取出来,这是为了提高页面的响应速度和用户体验。当前这两次请求URL完全相同,包括参数。这个时候,浏览器就不会与服务器交互。
两次请求的地址完全一致(包括参数),那么IE就会从缓存中取服务器上一次返回的结果。而不会从新向服务器发送请求。
测试方法:
先输入一个不存在的用户名,比如bbb,失去焦点,发送一次Ajax请求,然后不刷新页面。打开php文件,向数组中加入用户名bbb。回到浏览器,还不能刷新,再次失去焦点。如下图
如何解决IE缓存的问题:
1、在ajax发送请求前加上
xhr.setRequestHeader("If-Modified-Since","0"); //实测可用
2、在服务器端加
header("Cache-Control:no-cache");
header("Pragma:no-cache");
header("Expires:-1");
加入三个header,目的是让所有的浏览器都不缓存。
3、在 Ajax 的 URL 参数后加上
"?fresh=" + Math.random(); //当然这里参数 fresh 可以任意取了
4、第种方法和第3种类似,在 URL 参数后加上 "?timestamp=" + new Date().getTime();
5、用POST替代GET:不推荐
以上几种方式,比较推荐第3和第4中方法。
3、get和post请求
使用POST请求:
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
服务器接收数据用$_POST.
ajax中的get和post的一些说明:
①、用post请求,不会产生缓存。
②、用post请求的时候,能不能也用get,即post和get请求同时使用。答案是能,只不过get请求的参数用\(_GET获取,post请求的参数用\)_POST获取。
③、用$_REQUEST获取get和post方式提交的参数,如果参数名相同,获取的是谁?获取的是post的内容
4、同步、异步
同步请求,在同一个时间点上,只能有一个进程;其他进程只能等待。
异步请求,在同一个时间点上,可以同时进行多个进程。
open方法的第三个参数表示同步或者是异步请求。默认值true表示异步请求,false表示同步请求。
5、请求的url如果出错怎么办
以后写Ajax的时候,不但要判断readyState的值是否为4,还要判断http状态码status属性的值是否是200.
八、JSON
w3c手册位置:上面的javascript – 左侧的JSON
1、什么是json
json本质就是字符串,只不过这个字符串的格式有要求,格式要符合js中的数组或对象的格式。
"['apple', 'orange', 'banana']"
"{name:'zhangsan', age:20}"
更加复杂的情况:
"[{id:1, name:'宋江', age:30}, { id:2, name:'卢俊义', age:30}, { id:3, name:'吴用', age:30}]"
2、JSON有什么用
json在web开发中,它起到的作用和xml和的作用一样。具体来说,json可以当做配置文件,json文件可以存储数据,
json可以当做两种编程语言交换数据的媒介。
3、json和PHP进行转换
1、把PHP数据转化成json格式
使用json_encode()函数
$arr1 = ['apple', 'banana', 'pear'];
$arr2 = ['one'=>'LiuBei', 'two'=>'GuanYu', 'three'=>'CaoHao'];
//把上面两个数组,转换成JSON
$str1 = json_encode($arr1);
echo $str1; // ["apple","banana","pear"]
echo '<br>';
$str2 = json_encode($arr2);
echo $str2; // {"one":"LiuBei","two":"GuanYu","three":"CaoHao"}
//将str1和str2转成PHP数据
echo '<pre>';
print_r(json_decode($str1));
print_r(json_decode($str2, true));//加入true表示转回数组格式,否则默认对象形势
2、把json格式数据转化成PHP数据
json_decode(数组,true);//加入true表示转回数组格式,否则默认对象形势
4、json和JavaScript进行转换
1、把js数据转化成json
使用的方法是JSON对象的stringify()方法。
2、把json数据转化成js数据
方法一是使用JSON.parse(json字符串)方法;
方法二是使用eval函数。
5、小结
九、Ajax中,服务器返回json格式的数据
创建07json.html,向07json.php发送ajax请求。
服务器中的07json.php,返回一个数组。但是PHP的数据和JS的数组不一样,所以要转换成JSON格式,然后再返回:
再看07json.html,接收到服务器返回的数据(JSON格式),然后通过JSON.parse转换JS数据,就可以处理。
十、案例–省市县三级联动
1、资料说明
08city.sql 资料中,包含三张表,sheng、shi、xian。
查询所有的省:
select * from sheng;
查询河北省中的市:
select * from shi where ProvinceCode = 130000;
查询石家庄市的县:
select * from xian where CityCode = 130100;
2、创建所需文件
08city.html:
<select id="sheng">
<option value="0">--请选择省--</option>
</select>
<select id="shi">
<option value="0">--请选择市--</option>
</select>
<select id="xian">
<option value="0">--请选择县--</option>
</select>
08city.php,接收到浏览器发来的Ajax请求,连接数据库,获取省。获取完毕,转换成JSON类型返回给浏览器:
JS接收服务器返回的数据,并处理成JS数组,然后创建option,给option赋值value属性,并添加到select框中:
做这块的时候,要经常通过浏览器工具来查看错误。
最终效果是:
/全栈教程/04_JS/JS核心第11Ajax第2天
4、省切换的时候,获取市
给sheng绑定事件,执行Ajax请求:
PHP代码:
浏览器检测,没有问题。下面处理返回的结果:
5、市切换的时候,获取县
HTML代码:
PHP代码:
一个问题,省切换的时候,不但要重置市,还有重置县:
四、优化省市县三级联动
1、将数据库修改为文件
省市县的数据,不会经常变动,基本上可以认为是不变的数据。对于这样的数据,最好不要存到数据库,用文件存放也是一样的,而且用文件存放还可以减轻数据库的压力。所以用文件把省市县的数据存储,然后去查文件。
2、简化PHP代码
复制02city.html为03city.html。复制02city.php为03city.php
复制city文件夹到项目中:
查询省、市、县的时候都根据文件名去查找,并且约定浏览器请求的时候,要传递filename参数,参数的值就是文件名。
3、修改JS代码
4、简化JS代码
封装\(、chuli、get三个函数:
\) : 根据元素的id,返回dom对象
chuli : 传入要处理的数据,并且传入要放入的位置。
get :执行ajax请求,参数1是url地址,参数2是一个函数,用于处理服务器返回的数据。
chuli函数:
\(函数
![-w636](media/15714037815352/15714686776758.jpg)
get函数
![-w856](media/15714037815352/15714686873343.jpg)省市县获取代码:
![-w862](media/15714037815352/15714686985015.jpg)
==写的\)、get函数做什么项目都可以使用,可以将这两个函数写到一个js文件中。==