AJAX的具体使用
一、GET请求
①GET请求传递参数通常使用的是问号传参,即在请求地址上加上?参数,从而传递数据到服务端
②一般在GET请求数据时,无需设置响应体,可以传null或者干脆不传
③一般情况下URL传递的都是参数性质的数据,而POST一般都是业务数据
<?php //test.php服务端文件 //返回的响应就是数据,对于返回数据的地址一般称之为接口(有输入有输出),形式上上是web形式 $data=array( array('id' => 1,'name' =>'刘备','age' => 30), array('id' => 2,'name' =>'关羽','age' => 29), array('id' => 3,'name' =>'张飞','age' => 28) ); //处理数据 if(empty($_GET['id'])){ //没有ID则获取全部数据 //因为HTTP中约定报文的内容就是字符串,需要传递给客户端的是信息是一个有结构的数据 //这种情况下一般采用json作为数据格式 $json=json_encode($data); echo $json; }else{ //传递了ID只获取一条 foreach($data as $item){ if($item['id']==$_GET['id']){ $json=json_encode($item); echo $json; } } } ?>
<body> <ul id="list"></ul> <script> var listElement=document.getElementById("list"); var xhr=new XMLHttpRequest(); xhr.open('GET','http://localhost/test.php'); xhr.send(); xhr.onreadystatechange=function(){ if(this.readyState!==4) return; //JSON.parse()方法用于将一个JSON字符串转换为对象 var data=JSON.parse(this.responseText); //遍历对象 for(var i=0;i<data.length;i++){ //增加一个li元素 var liElement=document.createElement('li'); //li元素里面写入的是服务端数据的name值 liElement.innerHTML=data[i].name; //便于后面获取当前被点击元素对应数据的ID liElement.id=data[i].id; //把li元素添加到ul里面 listElement.appendChild(liElement); //为li元素注册点击事件,使用addEventListener的好处是可以为一个元素注册多个事件,不会冲突 liElement.addEventListener('click',function(){ //通过AJAX操作获取服务器端对应数据的信息 var xhr1=new XMLHttpRequest(); xhr1.open('GET','http://localhost/test.php?id=' + this.id); xhr1.send(); xhr1.onreadystatechange=function(){ if(this.readyState!==4) return; var obj = JSON.parse(this.responseText); console.log(obj); alert(obj.age); }; }); } } </script> </body>
二、POST请求
①post请求过程中,都是采用请求承载需要提交的数据
②open()方法的第一个参数就是设置请求的method
③setRequestHeader中需要设置Content-Type的格式与send( )里参数的格式相对应
④用户可以自定义加载页面,只要利用display的none和block结合请求的状态变化就可以实现
⑤案例:
<?php //test.php服务端文件 //接收用户端提交的用户名和密码 if(empty($_POST['username']) || empty($_POST['password'])){ exit('请提交用户名和密码'); } //校验 $username=$_POST['username']; $password=$_POST['password']; if($username==='admin' && $password='123'){ exit('登录成功'); } exit('用户名或者密码错误'); ?>
<body> <table border="1"> <tr> <td>用户名</td> <td><input type="text" name="username" id="username"></td> </tr> <tr> <td>密码</td> <td><input type="password" name="password" id="password"></td> </tr> <tr> <td></td> <td><button type="submit" id="btn">登录</button></td> </tr> </table> <script> //声明变量 var btn=document.getElementById("btn"); var txtUsername=document.getElementById("username"); var txtPassword=document.getElementById("password"); //为btn注册点击事件 btn.onclick=function(){ //获取用户填入的值 var username=txtUsername.value; var password=txtPassword.value; //通过xhr发送一个POST请求 var xhr=new XMLHttpRequest(); xhr.open('POST','http://localhost/test.php'); //设置请求头的格式,与请求体urlencoded的格式对应 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //设置请求体,格式为urlencoded,注意`{}`这样的写法 xhr.send(`username=${username}&password=${password}`); //根据服务端的反馈,作出页面提示 xhr.onreadystatechange=function(){ if(this.readyState!==4) return; console.log(this.responseText); } }</script> </body>
三、同步和异步
①概念
- 同步可以理解为一个人在同一时刻只能做一件事情,在执行一些耗时的操作(不需要看管)不去做其他的事,只是等待。同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。
- 异步可以理解为在执行一些耗时的操作时(不需要看管)去做别的事,而不是等待。将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。
②设置:open()方法第三个参数是传入一个bool值,其作用就是设置此次请求是否采用异步方式执行 ,默认为true,如果需要同步执行可以通过传递false实现
<script> console.log('before ajax'); var xhr=new XMLHttpRequest(); xhr.open('GET','http://localhost/test.php',true); xhr.send(null); xhr.onreadystatechange=function(){ if(this.readyState===4){ console.log('加载完成'); } } console.log('after ajax'); //控制台输出: //before ajax //after ajax //加载完成 </script>
<script> var xhr=new XMLHttpRequest(); xhr.open('GET','http://localhost/test.php',false); //同步方式执行会在send()发送请求以后等待一段时间,直到readyState为4才会继续往下执行代码 xhr.send(null); //所以不需要注册事件,就可以拿到数据了,或者如果需要注册事件,一定需要在send方法调用之前注册事件,否则无法触发 console.log(xhr.readyState);//4 // xhr.onreadystatechange=function(){ // if(this.readyState===4){ // console.log('加载完成'); // } // } console.log(xhr.responseText);//1529918265 //并且控制台会提醒这种方式会导致用户体验不佳: //[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. </script>
③结论:
- 同步,是所有的操作都做完,才返回给用户结果。即写完数据库之后,在相应用户,用户体验不好。
- 异步,不用等所有操作等做完,就相应用户请求。即先相应用户请求,然后慢慢去写数据库,用户体验较好。
四、响应数据类型
- 如果服务端返回的各种格式的数据,这种格式的数据都需要在客户端使用JavaScript解析
- XML是一种数据描述手段,由于数据冗杂太多,现在基本被淘汰
<?xml version="1.0" encoding="utf-8" ?> <users> <user> <username>张三</username> <age>23</age> </user> <user> <username>李四</username> <age>24</age> </user> </users>
<script> var xhr=new XMLHttpRequest(); xhr.open('GET','user.xml'); xhr.send(); xhr.onreadystatechange=function(){ if(this.readyState!==4) return; var name1=this.responseXML.documentElement.getElementsByTagName("username")[0].innerHTML; var age1=this.responseXML.documentElement.getElementsByTagName("age")[0].innerHTML; console.log(name1+":"+age1);//张三:23 } </script>
- JSON也是一种数据描述手段,类似于JavaScript字面量方式,服务端采用JSON格式返回数据,客户端按照JSON格式解析数据
[ { "username" : "张三", "age" : 23}, { "username" : "李四", "age" : 24} ]
<script> var xhr=new XMLHttpRequest(); xhr.open('GET','user.json'); xhr.send(); xhr.onreadystatechange=function(){ if(this.readyState!==4) return; var obj=JSON.parse(this.responseText); var name2=obj[1].username; var age2=obj[1].age; console.log(name2+":"+age2);//李四:24 } </script>
- 不管服务端采用的是XML格式的数据还是JSON格式的数据,本质上都是将数据返回给客户端
- 服务端应该设置一个合理的Content-Type
五、其他
①response获取到的结果会根据responseType的变化而变化,而responseText永远获取的都是字符串形式的响应体
<script> var xhr=new XMLHttpRequest(); xhr.open('GET','test.php'); xhr.send(); //responseType还允许作者将响应类型更改为一个"arraybuffer", "blob", "document", "json", 或 "text" 。 //如果将一个空字符串设置为responseType的值,则将其假定为类型“text”,即 "" 等效于 "text"; //兼容性不是很好,推荐使用responseText xhr.responseType=''; xhr.onreadystatechange=function(){ if(this.readyState!==4) return; console.log(this.response); } </script>
②兼容方案:XMLHttpReuquest在老版本浏览器(IE5/6)中有兼容问题,可以通过另外一种方式代替
//兼容IE5/6
var xhr=window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHttp");
③补充:Chrome中控制台展开被打印的对象时,会访问即时的数据
<script> var obj={foo:123}; console.log(obj); setTimeout(function(){ obj.foo=456; console.log(obj); },3000) //说明: //打开控制台,如果先打开{foo: 123},还未出现{foo: 456},看到的前面foo的值是123,后面foo的值是456; //打开控制台,如果{foo: 123}和{foo: 456}都已经显示,打开任何一个看到的值都是456 </script>
【转载文章务必保留出处和署名,谢谢!】