传统网站中存在的问题:
1.网速慢的情况下,页面加载时间长,用户只能等待
2.用户提交表单后,由于页面发生跳转,如果表单中有一项内容不符合要求,页面就会被重新跳转回表单填写页面,此时用户刚刚填写的内容由于页面跳转,没了。所以用户需要再重新填写所有表单的内容。
3.页面跳转过程中,需要重新加载整个页面,但是一般网站中每个页面的头部、底部、侧边栏都是一样的,重新向服务器发起请求,浏览器响应内容并渲染页面,增加了用户等待的时间。
=======> Ajax技术解决
Ajax概述
Ajax是浏览器提供的一套方法,通过调用这些方法,可以实现客户端向服务器端发送请求,实现在不刷新页面的情况下,更新页面的数据,由于页面不需要更新,所以在服务器端没有做出响应之前,浏览网站的用户不需要等待,可以继续浏览网站中其他内容。
简单来说,就是Ajax可以实现在用户浏览网页过程中,局部更新页面数据。
Ajax的应用场景
1.页面上拉加载更多数据(就是页面向上滑动,当滑动到页面底部时,无刷新更新页面中的数据)
2.列表数据无刷新分页(从第一页切换到第二页时,只有列表数据发生变化,页面中其他数据完全没有变化,比如网站头部、底部、侧导航)
3.表单数据验证,比如验证邮箱地址的唯一性,当用户在邮箱表单控件中,输入完邮箱地址离开焦点以后,可以使用Ajax技术向服务端发送请求,问一下服务器端,当前用户填写的邮箱地址是否被别人注册过,如果注册过,马上告诉当前用户这个邮箱地址被注册过,如果没注册过,告诉用户当前邮箱地址可用。——可以避免当用户将表单整体填完提交到服务器端以后,再提示用户邮箱地址不可用,避免页面跳转,用户重新提交表单的情况。
4.搜索框文字自动提示功能,(当我们在搜索框输入内容时,内容下方提示一系列相关文字,这些文字都是在用户输入内容过程中使用Ajax技术向服务器端发送请求,请求过来的,如果请求来的内容正好是用户需要的,用户可以直接选择需要的内容,不用继续输入,从而提高用户体验)
.....
Ajax技术在现代网站应用中,主要应用在不刷新页面情况下,向服务器发送请求和服务器端进行交互,从而更改客户端页面中的数据或状态。
Ajax的运行环境
Ajax需要运行在网站环境才能生效
Ajax的运行原理
传统网站:浏览器向服务端发送请求,浏览器接收服务器端响应的客户端数据。浏览器在发送请求和接受请求期间,不能再响应用户的其他操作,比如继续浏览并拉动当前页面,所以用户体验感不好。
现在:在用户浏览当前网站期间,向服务器发送请求,并将请求数据在不刷新页面情况下,更新在页面中。所以,请求的发送和接收不能由浏览器自己做,要找一个代理帮忙做这个事。Ajax就是浏览器代理人,Ajax帮浏览器向服务器发送请求,由Ajax帮浏览器接受服务器端响应到客户端的数据,当Ajax接受到数据后,使用DOM方法,将服务器端发送的数据内容添加到页面中。
注意:在传统情况中,请求的发送和接收是开发人员不可控的,而使用Ajax技术,开发人员可控请求的发送和接收。
Ajax的实现步骤:
1.创建Ajax对象
var xhr=new XMLHttpRequest();
2.告诉Ajax我想要请求的服务器端地址是什么?方式是什么?
xhr.open('get','https://www.example.com');
3.发送请求
xht.send();
4.获取服务器端给客户端的响应数据
(因为请求受网络快慢的影响,这个请求时间是个不确定的时间,所以我们不能在send后面直接获取请求结果)
xhr.οnlοad=function(){
console.log(xhr.responseText);
}
服务器端响应的数据格式:
服务器端大多数会以JSON对象作为响应数据的格式。当客户端拿到JSON数据时,会将JSON数据与HTML进行拼接,再将拼接好的HTML字符串使用DOM操作方式追加到页面当中。JSON数据与HTML进行拼接这一步骤拿到客户端做,不再拿到服务器端做了。
在http请求与响应过程中,无论是请求参数还是响应内容,如果是对象类型,最终都会被转换为对象字符串进行传输。
JSON.parse();//将json字符串转为json对象
xhr.οnlοad=function(){
var responseText=JSON.parse(xhr.responseText);
var str='<h2>'+responseText.name+'</h2>';
document.body.innerHTML=str;
}
请求参数传递
传统方式:表单提交
get的请求方式:
xhr.open('get','http://www.example.com?name=lkq&&password=123');
<body>
<p>
用户名:<input type='text' id='username'>
</p>
<p>
密码: <input type='text' id='password'>
</p>
<p>
<input type='button' value='提交' id='btn'>
</p>
<script>
var btn=document.getElementById('btn');
var username=document.getElementById('username');
var password=document.getElementById('password');
btn.οnclick=function(){
var xhr=new XMLHttpRequest();
var nameValue=username.value;
var passwordValue=password.value;
var params='username='+nameValue+'&password='+passwordValue;
xhr.open('get','http://localhost:300/get?'+params);
xhr.send();
xhr.οnlοad=function(){
console.log(xhr.responseText);
}
}
</script>
</body>
post的请求方式
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');//固定写法
xhr.send('name=lkq&&password=123');
<script>
var btn=document.getElementById('btn');
var username=document.getElementById('username');
var password=document.getElementById('password');
btn.οnclick=function(){
var xhr=new XMLHttpRequest();
var nameValue=username.value;
var passwordValue=password.value;
var params='username='+nameValue+'&password='+passwordValue;
xhr.open('post','http://localhost:300/post?');
//post请求必须设置请求参数格式类型
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(params);//放到send()后,就把这个参数放到请求体中了
xhr.οnlοad=function(){
console.log(xhr.responseText);
}
}
</script>
请求参数格式
1.application/x-www-form-urlencoded
name=20&&sex=男
2.application/json(在请求头中指定content-type的属性值是application/json,告诉服务器当前请求参数的格式是json,将Json转为json字符串,再放入set方法中)
{
name:'zhangsan',
age:'20',
sex:'男'
}
JSON.stringify() //将json对象转换为json字符串
<script>
var xhr=new XMLHttpRequest();
xhr.open('post','http://localhost:3000/json');
//设置请求头中content-type属性,告诉客户端向服务端传递的请求参数格式是什么
xhr.setRquestHeader('Content-Type','application/json');
xhr.send(JSON.stringify({name:'lkq',age:99}));
xhr.οnlοad=function(){
console.log(xhr.responseText);
}
</script>
注意:get请求是不能提交第二种格式的,传统网站的表单提交也是不支持json对象数据格式的。
Ajax状态码
0:请求未初始化(还没调用open())
1:请求已经建立,但是还没有发送(还没有调用send())
2:请求已经发送
3:请求正在处理中,通常是已经接收了部分数据了
4:响应已经完成,可以获取并使用服务器响应的数据了
xhr.readyState;//获取Ajax状态码
当Ajax状态码发生变化时会自动触发该事件:onreadystatechange,可以在该事件中输出Ajax状态码
Ajax错误处理(当请求结果不是预期结果时,怎么处理)
1.当网络畅通,服务器接收到请求,服务器端返回的结果不是预期结果(比如客户端发送的请求参数不符合要求,服务器端返回非200状态码)
在Ajax中怎么获取http状态码?=> xhr.status;
<script>
var btn=document.getElementById('btn');
btn.οnclick=function(){
var xhr=new XMLHttpRequest();
xhr.open('get','http://locathost:3000/error');
xhr.send();
xhr.οnlοad=function(){
console.log(xhr.responseText);
if(xhr.status==400){
alert('请求出错');
}
}
}
</script>
2.网络畅通,服务器端没有接收到请求,返回404状态码(需要检查请求地址是否拼写错误)
3.网络畅通,服务器端能接收请求,但返回500状态码(可以找服务器端的开发人员)
4.网络中断,请求无法发送到服务端(这种情况不会触发xhr下面的Onload事件,但会触发xhr下的onerror事件)
<script>
var btn=document.getElementById('btn');
btn.οnclick=function(){
var xhr=new XMLHttpRequest();
xhr.open('get','http://locathost:3000/error');
xhr.send();
xhr.οnlοad=function(){
console.log(xhr.responseText);
if(xhr.status==400)
alert('请求出错');
}
xhr.οnerrοr=function(){
alert('网络中断');
}
}
</script>
Ajax状态码:表示Ajax请求的过程状态,是Ajax对象返回的
http状态码:表示请求的处理结果,是服务器端返回的
Ajax技术在IE低版本浏览器的缓存问题
在低版本IE中,Ajax请求有严重的缓存问题,在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务器,后序请求都会从浏览器的缓存中获取结果,即使服务器端的数据更新了,客户端拿到的依然是缓存中的旧数据。
ie低版本不支持onload所以改成onreadystatechange
解决方案:在请求地址后面加请求参数,保证每一次请求参数的值不相同,这样就不会从缓存中获取数据了
xhr.open('get','http://www.example.com?t=' +Math.random());
<script>
var btn=document.getElementById('btn');
btn.οnclick=function(){
var xhr=new XMLHttpRequest();
xhr.open('get','http://locathost:3000/cache?t='+Math.random());
xhr.send();
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.state==200)//等于4只说明服务端数据接收完了,但要是是错误的数据呢?需要判断http状 //态 码
alert(xhr.responseText);
}
}
</script>
Ajax的封装
问题:发送一次Ajax请求,就发送很多的代码,发送多次请求,代码冗余且重复
解决方法:将请求代码封装到函数中,发请求时调用函数
ajax({
type:'get',
url:'http://www.example.com',
success:function(data){
console.log(data);
}
})
<script>
function ajax(options){
var defaults={
type:'get',
url:'',
data:{},
header:{
'Content-Type':'application/x-www-form-urlencoded'
},
success:function(){},
error:function(){}
};
Object.assign(defaults,options);//用覆盖来实现,传了就用传的,没传就用默认的,用options属性覆盖default中对象属性
//创建ajax对象
var xhr=new XMLHttpRequest();
var params='';
//参数转为字符串形式
for(var str in options.data){
params+=str+'='+options.data[str]+'&';
}
params=params.substr(0,params.length-1);//将最后的&截取掉
//判断是get还是post,get放在url后,post放Send()
if(options.type=='get'){
options.url=options.url+'?'+params;
}
xhr.open(options.type,options.url);
if(options.type=='post'){
var contentType=options.header['Content-Type'];
//设置参数格式类型
xhr.setRequestHeader('Content-Type',contentType);
if(contentType=='application/json')
xhr.send(JSON.stringify(options.data));
else
xhr.send(params);
}else
xhr.send();
xhr.οnlοad=function(){
//获取响应头的数据
var contentType=xhr.getResponseHeader('Content-Type');
var responseText=xhr.responseText;
if(contentType.includes('application/json')){
responseTetx=JSON.parse(responseText);//将JSON字符串转为JSON对象
}
//当Http状态码为200时
if(xhr.status==200)
options.success(responseText,xhr);//请求成功调用成功情况的函数
else
options.error( responseText,xhr);//请求失败,调用处理失败情况的函数
}
}
ajax({
ulr:'http://www.example.com/first',
success:function(data,xhr){//希望请求成功被调用
console.log(data);
},
error:function(data,xhr){
console.log(data);
}
});
//需求:发送请求的时候向服务器端传递一些请求参数,get是将请求参数拼接到url后面,post是需要放在请求体中,Send()
//服务器在返回数据时候,会在响应头中设置数据返回类型,只需要获得这个类型,然后进行判断,如果返回JSON类型数据,再转换,不是就不转换。——xhr.getResponseHeader();获得响应头的数据