ajax原理及使用案例
一、什么是ajax?
ajax用来和服务器进行交互,即前端与后端进行交互的桥梁。
二、ajax的特点:
提交少量数据;
异步;
补充:异步和同步【异步:同时分开执行】【同步:按顺序执行】
提高程序的执行效率;
提高用户体验;
减少宽带。
三、ajax的作用:
无刷新页面。
四、ajax原理(代码展示):
/*创建ajax对象:XMLHttpRequest是一个内置函数,所以ajax对象是new出来的对象;需要做兼容: 标准浏览器:var xhr = new XMLHttpRequest; ie浏览器:var xhr = new ActiveXObject('Microsoft.HMLHTTP') */ var xhr = window.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject('Microsoft.HMLHTTP'); /*与服务器建立连接:有三个参数: 第一个参数:get/post ajax一般采用get传值,因为get是路径传值,而且传递的数据少,符合ajax传少量值的特点。 get和post的区别:get:路径传值;传递的数据少;传递的数据用户可见;便于调试;安全度低; post:非路径传值;传递的数据相对get多;传递的数据用户不可见;不便于调试;安全度相对于get高; 第二个参数:路径; 第三个参数:布尔值(是否异步:TRUE--异步--默认值) */ xhr.open('GET','1.txt',true); //发送请求: xhr.send(); //通过服务器处理数据并返回处理结果 xhr.onreadystatechange = function(){ /*判断状态值: 0:请求还未初始化; 1:请求已建立,还未发送 2:请求已发送,还未处理 3:处理部分请求 4:请求处理完成 */ if(xhr.readyState === 4){ /*判断状态码: 404:路径错误; 200:交易成功; 400:服务器语法错误; 500:服务器内部错误; */ if(xhr.status === 200){ //alert(xhr.responseText); oDiv.innerHTML = xhr.responseText; } } }
文字叙述ajax的工作原理:
通过创建XMLHttpRequest对象;
通过open与服务器建立连接;
通过send将请求发送给后端;
通过onreadystatechange事件监听后端状态;
当readyState返回值的状态是4,并且Status返回码的状态是200时,表示服务器已找到请求的数据并通过回调函数将响应的responseText数据返回给前端,如果返回404,则表示没有找到请求的数据,即路径错误。
五、ajax的缓存问题(以点击指定按钮显示指定数据为例):
ajax.html文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> div{ width:300px; height:100px; border:1px solid black; } </style> </head> <body> <p><button id = "btn1">认识kinoko</button></p> <p><button id = "btn2">了解kinoko</button></p> <p><button id = "btn3">熟悉kinoko</button></p> <div id = "box"></div> </body> </html> <script src= "ajax.js"></script> <script> //获取按钮: var obtns = document.getElementsByTagName('button'); var oDiv = document.getElementById('box'); for(let i =0 ,len=obtns.length;i<len;i++){ obtns[i].onclick = function(){ var xhr = window.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject('Microsoft.HMLHTTP'); xhr.open('GET',(i+1)+'.txt?t='+new Date().getTime());//注意此处路径的写法,因为使用let声明变量,不会提升变量,所以i可以直接拿来用; //如果用var声明变量,则需要给i重新定义:obtns[i].index = i;此时路径为:(i+1)+'.txt';或者不给i重新定义,路径为 //this.index+'.txt'. xhr.send(); xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ if(xhr.status === 200){ oDiv.innerHTML = xhr.responseText; } } } } } </script>
txt文件:
1.txt
你好!
欢迎来到kinoko的世界。
kinoko衷心款待大神哦!
2.txt
kinoko是一个只喝露水的小仙女;
一定要善待她哦!
3.txt
哈哈哈.......
是不是有点喜欢她呢?
只能回答yes!
我们知道ajax的作用是无刷新页面,正常情况只要我们对txt做了改动,在不刷新页面的情况下点击按钮,会自动更新内容。但当我们使用ie浏览器运行以上代码时,会发现更新txt文件时,点击按钮,页面并不会去更新,这个bug就是ajax的缓存问题,要解决这个问题,我们得先知道为什么会存在这个bug,什么原因导致的,当浏览器多次请求同一个文件时,如果路径不发生改变,后面的多次请求就直接从浏览器缓存拿数据,导致了服务器发生更改时,就无法拿到服务器的数据。
究其本质是因为路径是不变的,所以要解决这会bug,我们是不是应该考虑:浏览器每访问一次该文件,让它的路径发生改变。
解决方法:
方法一:在路径后面加一个一直在变的参数
1.url?id=Math.random();
2.url ?id=new Date().getTime();
这个方法会在浏览器产生缓存,用起来并不会很ok
方法二:手动在浏览器清除缓存
这个方法虽然可以解决这个bug,但不推荐使用
方法三:
添加请求头:xhr.setRequestHeader('if-modified-since','0');[比较服务器上最后文件的修改时间,如果时间一样,则直接从浏览器缓存获取数据;如果不一样,则先清除浏览器之前的缓存,再从服务器获取更新后的数据。不会有过多的缓存,推荐使用]写在open和send的中间。
六、ajax跨域问题:
在说ajax跨域之前先说一下同源策略;
1、同源策略:是浏览器的保护机制,为了保护用户信息的安全;同源指协议、域名、端口号保持一致;
使用ajax请求服务器数据时,要保证协议、域名、端口号和ajax请求的路径完全一致;
因为同源策略,ajax不能跨域;
jsonp是我们用来解决ajax跨域问题的。
2.jsonp:
jsonp工作原理:
动态创建一个script标签,添加到body中;
设置script的src属性,src属性的值是一个接口,即路径,在路径上有一个特殊参数:回调函数;
服务器通过对回调函数的调用,使用参数传递的方式将服务器处理的结果传回客户端。
3.jsonp接口和ajax接口的区别:
jsonp接口有一个特殊的参数--回调函数,ajax没有;
jsonp是路径传值,所以只支持get传递,ajax同时支持get和post;
jsonp返回的是对象,ajax返回的是字符串。
具体以代码展示:
jsonp.html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> </body> </html> <script> document.onclick = function(){ //动态创建script标签: var labelScript = document.createElement('script'); //将script标签加到body中; document.body.appendChild(labelScript); // alert(labelScript); //设置script标签的src属性: labelScript.src = "http://localhost/ajax/jsonp/jsonp.php?cb=fn"; } //通过对回调函数的调用,利用参数传递将服务器处理的结果返回客户端。这个函数必须是全局函数。 function fn(msg){ alert(msg);//此处输出的是服务器echo出的数据。控制台输出:[object object] } </script>
jsonp.php文件:
<?php //接受客户端传递的数据,因为是路径传值,所以只能用get获取: $fun = $_GET['cb']; //创建一个伪服务器: $arr = array('uname'=>'liyabixa'); //将数组转成json对象: $jso = json_encode($arr); //通过回调函数将处理后的结果利用参数传递返回给客户端: //此处echo出的就是服务器处理后的数据,也就是要返回给客户端的数据。 echo $fun."(".$jso.")"; ?>
七、案例:
1、 定义一个json文件 加载产品列表
Json文件
[
{"pid":"01","pname":"苹果","price":12},
{"pid":"02","pname":"香蕉","price":23},
{"pid":"03","pname":"火龙果","price":56}
]
通过ajax 获取这些json数据,并将这些产品信息 动态的显示在页面中
product.html文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> td{ text-align: center; } </style> </head> <body> <table id = "table" border = 1 width = 300 cellspacing = 0> </table> </body> </html> <script src = "ajax.js"></script> <script> otable = document.getElementById('table'); ajaxGet('product.json',function(data){ //此处data数据就是json文件中的数据,ajax输出json时字符串,所以需要将字符串转成对象; var arr = JSON.parse(data); // console.log(arr); //声明一个容器来存放数据: var con = ""; //遍历数组: for(var i = 0,len=arr.length;i<len;i++){ //console.log(arr[0].pid); //模板字符串中嵌入变量,要将变量名写在${}之中。 //大括号内可以放入任意的JavaScript表达式,可以进行运算,以及引入对象属性。 con += `<tr><td>${arr[i].pid}</td><td>${arr[i].pname}</td><td>${arr[i].price}</td></tr> `; } //将容器con中的数据放到table中。 otable.innerHTML = con; }) </script>
product.php文件:
[ {"pid":"01","pname":"苹果","price":12}, {"pid":"02","pname":"香蕉","price":23}, {"pid":"03","pname":"火龙果","price":56} ]
2、 定义一个json数据:
根据数据 实现 百度智能联想效果
[
{"pname":"iphone"},
{"pname":"苹果ipad"},
{"pname":"hongmi"},
{"pname":"xiaomi"}
]
文本框 :
idea.html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> li{ list-style: none; color:blue; } </style> </head> <body> <input type="text" id = "ipt"> <ul id = "ul"> </ul> </body> </html> <script src= '../homework1/ajax.js'></script> <script> //获取页面元素: var oipt = document.getElementById('ipt'); var oul = document.getElementById('ul'); //给oipt添加键盘弹起事件: oipt.onkeyup = function(){ //不清空oul,每触发一次弹起事件,就显示一次内容,所以需要清空oul oul.innerHTML = ""; //通过ajax获取服务器数据: ajaxGet('idea.json',function(data){ var arr = JSON.parse(data); var con = ""; for(var i=0,len=arr.length;i<len;i++){ //console.log(arr[1].pname); //创建li元素并放入ul中 var oli = document.createElement('li'); //console.log(oli); oli.innerHTML = arr[i].pname; if(arr[i].pname.indexOf(oipt.value)!=-1){ oul.appendChild(oli); } } }) } </script>
idea.php文件:
[ {"pname":"iphone"}, {"pname":"苹果ipad"}, {"pname":"hongmi"}, {"pname":"xiaomi"} ]
附件--ajax.js文件:
function ajaxGet(url,callback,data){ var xhr = window.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject('Microsoft.HMLHTTP'); xhr.open("get",url); xhr.send(); xhr.onreadystatechange = function(){ if( xhr.status==200&&xhr.readyState==4 ){ //通过函数调用的方式 将服务器处理的结果通过参数返回 callback(xhr.responseText); } } }
三、分页
list.html文件:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="main.css" /> <style> .header{ height: 40px; width: 900px; margin: 0 auto 50px; } #box{ width: 300px; height: 30px; border: 1px solid black; float: left; margin-left:500px; } #box li{ list-style: none; display: inline-block; padding: 0 5px; float: left; } #box li.active{ color: red; background-color: green; } #box ul{ /* float: left; */ display: inline-block; } </style> </head> <body> <ul class="shoplist clearfix" id="main"> <!--<li> <img src="img/1.jpg" alt="" /> <p>小米1</p> <p>999</p> <button>购买</button> </li>--> </ul> <div id="box"> <span id="left">上一页</span> <ul id="u"> <li>1</li> <li>2</li> <li>3</li> </ul> <span id="right">下一页</span> </div> </body> </html> <script src="ajax.js"></script> <script> /*思路: 1.通过ajax获取json中的数据,因为ajax获取的数据是string,所以需要将字符串转成对象, */ //获取页面元素: var u = document.getElementById('main'); var uu = document.getElementById('u'); var index = 1; var pagenum=4; //console.log(u); page(); function page(){ ajaxGet('data.json',function(data){ //将字符串转成对象; var arr = JSON.parse(data); console.log(arr); //声明一个空容器来存放数据: var con = ""; //遍历数组: //遍历数组的同时要考虑到一行放几张图片: for(var i =(index-1)*4;i<index*pagenum;i++){ //判断最后一排的数量,此处不判断,最后一排不会显示,因为一共4页,一页4张,所有第五页的就不会显示; if(i<17){ //用字符串模板来创建li标签,在创建li标签的同时将json中的数据放到li标签中: con += `<li> <img src="img/${arr[i].src}" alt="" /> <p>${arr[i].name}</p> <p>${arr[i].price}</p> <button>购买</button> </li>` } } //将li放到ul中: main.innerHTML = con; //确定页数:数组的长度/一页的数 var total = Math.ceil(arr.length/pagenum); var page = ""; for(var i = 1; i<total-1;i++){ page += `<li>${i}</li>` } uu.innerHTML=page; //当前页码index高亮显示: uu.children[index-1].className="active"; }) } //添加点击事件: //点击页码:所有的li都需要添加点击事件,所以通过事件委托给li添加点击事件: uu.onclick = function(e){ //做事件兼容: var e = e || event; //做事件源兼容: var target = e.target ||e.srcElement; if(target.tagName == 'LI'){ index = target.innerHTML;//用tagName来获取标签,返回值是大写的。 page(); } } //上一页: left.onclick = function(){ index--; if(index==0){ index=1; }else{ page(); } } //下一页: right.onclick = function(){ index++; if(index==6){ index = 5; }else{ page(); } } </script>
附件1--ajax.js
// url :请求路径 // callback : 该参数是一个函数,回调函数 // data : 接口的参数 function ajaxGet(url,callback,data){ var ajax = null; if( window.XMLHttpRequest ){ ajax = new XMLHttpRequest(); }else{ ajax = new ActiveXObject("Microsoft.XMLHTTP"); } if(arguments.length == 3){//表示传递的参数有三个 url = url + "?" + data; } ajax.open("GET",url,true); ajax.onreadystatechange = function(){ if( ajax.readyState == 4 && ajax.status == 200 ){ if(callback){ callback(ajax.responseText);//通过函数的调用将服务器处理的结果以参数形式传递给前端 } } } ajax.send(); } function ajaxPost(url,callback,data){ var ajax = null; if( window.XMLHttpRequest ){ ajax = new XMLHttpRequest(); }else{ ajax = new ActiveXObject("Microsoft.XMLHTTP"); } ajax.open("POST",url); //设置请求头: ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); ajax.onreadystatechange = function(){ if(ajax.readyState == 4 && ajax.status == 200){ callback(ajax.responseText); } } ajax.send(data);//向服务器端发送数据 用户名 }
附件2--data.json:
[ { "id" : "shop01", "name" : "小米1", "src" : "9.jpg", "price" : "999" }, { "id" : "shop02", "name" : "小米2", "src" : "2.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米3", "src" : "3.jpg", "price" : "999" }, { "id" : "shop04", "name" : "小米4", "src" : "4.jpg", "price" : "999" }, { "id" : "shop05", "name" : "小米5", "src" : "5.jpg", "price" : "999" }, { "id" : "shop06", "name" : "小米6", "src" : "6.jpg", "price" : "999" }, { "id" : "shop07", "name" : "小米7", "src" : "7.jpg", "price" : "999" }, { "id" : "shop08", "name" : "小米8", "src" : "8.jpg", "price" : "999" }, { "id" : "shop09", "name" : "小米9", "src" : "9.jpg", "price" : "999" }, { "id" : "shop10", "name" : "小米10", "src" : "10.jpg", "price" : "999" }, { "id" : "shop01", "name" : "小米11", "src" : "9.jpg", "price" : "999" }, { "id" : "shop02", "name" : "小米12", "src" : "2.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米13", "src" : "3.jpg", "price" : "999" }, { "id" : "shop02", "name" : "小米14", "src" : "2.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米15", "src" : "3.jpg", "price" : "999" }, { "id" : "shop02", "name" : "小米16", "src" : "2.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" }, { "id" : "shop03", "name" : "小米17", "src" : "3.jpg", "price" : "999" } ]
附件3--main.css:
*{ border: 0; padding: 0; margin: 0; } ul,li,ol{ list-style-type: none; } /* ie 6/7 */ .clearfix{ *zoom : 1; *height: 1px; } /* IE8+ */ .clearfix:after{ content: ""; height: 0; clear: both; display: block; visibility: hidden; } .nav{ width: 900px; border: 1px solid red; margin: 0 auto; } .nav > span{ display: inline-block; float: left; width: 100px; height: 40px; text-align: center; line-height: 40px; padding: 10px 0; border-right: 1px solid red; cursor: pointer; } .nav > span.cur{ color: red; } .shoplist{ width: 900px; display: block; margin: 50px auto 0; } .shoplist > li{ width: 200px; /*height: 200px;*/ border: 1px solid #d1d1d1; text-align: center; float: left; margin-right: 10px; margin-bottom: 10px; } .shoplist > li button{ font-size: 24px; margin-top: 10px; cursor: pointer; border: 1px solid #000; } .shoplist > li img{ height: 150px; display: inline-block; } .shoplist > li p{ width: 100%; height: 20px; margin-top: 5px; }