Ajax也是前端必备技能了,学习任何语言,都需要以理论为基础的大量实践才能真正学会,之前学了Ajax很多遍,因为缺乏大量实践,总是会忘。所以不实践是失败之母。。。当然理论基础也很重要啦,今天谈谈我对Ajax的基础认知。
定义:全称:Asynchronous JavaScript and XML(用异步的形式的JavaScript去操作XML) 用来传输进行数据交互 其实就是拿数据发数据。
作用: 传统的数据提交,大多是通过表单的形式,填写数据,点击提交,数据就会被提交到后端,这种提交往往会跳转页面,存在很多问题,比如我们填完信息点了提交,就会跳到后端页面,后端页面进行验证,发现用户已经注册了,这个时候又会跳转到表单填写页面,让我们回去重新填,那之前填的全没了,肯定体验很不好。而Ajax就是能做到私底下去请求页面传递数据,然后返回给我们请求的结果,我们前端接收到这个结果,根据结果可以做一些操作,比如提示错误信息,整个页面是一直处在表单填写界面,从未跳转。想想我们平常注册帐号的时候,是不是没跳转界面就知道自己哪填的不对了,就是ajax在起作用。
下面我们先不解析具体的原理,先来看一个大致的实现过程。
首先,你得知道是把代码放在服务器下运行的,打开的时候不能用本地的地址,要用localhost/。。这种形式才是在服务下访问的。要是这不了解的话,可以先自行百度下。我平常都是用的xampp第三方集成的服务器,比较轻便。
需求:新建一个文字1.txt,随便输入什么内容,新建HTML页面,点击HTML页面里的按钮发生请求获取1.txt里面的内容。这里只看js代码。
复制代码
var oBtn = document.getElementById(‘btn’);
oBtn.onclick = function(){
var xhr = new XMLHttpRequest(); //创建Ajax对象
xhr.open(‘get’,‘1.txt’,true); //设置请求信息
xhr.send(); //提交请求
//等待服务器返回内容
xhr.onreadystatechange = function() {
if ( xhr.readyState == 4 ) { //判断当前的请求状态,4代表后端已经处理完成
alert( xhr.responseText ); //弹出内容
}
}
}
复制代码
当点击按钮的时候,你就会发现弹出了1.txt里面的内容。
我们来具体解析一下这个步骤
var xhr = new XMLHttpRequest(); //创建Ajax对象
我们要用Ajax获取数据,首先呢,要创建一个Ajax对象,就跟你想获取系统时间要创建一个时间对象是一个道理。对象的名称就是 XMLHttpRequest(),创建好之后我们就可以用对象下的方法属性进行数据交互了。
需要说明的是,这个对象实际是存在兼容问题的,IE6以下没有这个对象的,所以是获取不到数据的,IE6以下用的实际是一个插件的方式:
ActiveXObject(‘Microsoft.XMLHTTP’)
//ActiveXObject: IE6下插件的总称,包含很多插件
//Microsoft.XMLHTTP:具体某个插件的名字
所以我们需要对上面做一个兼容性的处理:
复制代码
var xhr = null;
if(window.XMLHttpRequest){ //加window是因为如果直接判断IE下不存在的东西会报错,加了window,就是在判断一个属性是否存在,这样就不会报错了(当然我们都知道所有的东西都在window对象下,所以这样判断是有效的)
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject(‘Microsoft.XMLHTTP’);
}
复制代码
接着看
xhr.open(‘get’,‘1.txt’,true); //设置请求信息
Open方法:有三个参数
1、提交方式 Form-method(get/post)
2、提交地址 Form-action
3、是否异步,是为(true)
首先讲提交方式:get/post 这两种的区别。
这里我们不用ajax的方式,先直接通过传统的表单提交数据来分析。
传统的表单提交就是在表单里面设置提交的一些参数,用户的输入信息点击提交,会跳到指定的后台页面。
表单form标签的属性:
action:提交到哪里 默认是当前页面
method:提交方式 默认是Get
enctype: 提交的数据格式,默认是application/x-www-form-urlencoded
我们来具体看个get方式请求的栗子,并且了解前后端到底是怎么交互的。
栗子需求:建立HTML页面,PHP页面,填入数据,点击提交,然后输出我们输入的内容。
HTML页面:
1.get.php(如果不了解PHP语言,大概看下面的注释简单知道干啥就行了)复制代码
<?php header('content-type:text/html;charset="utf-8"'); //设置编码格式,以及文档类型 error_reporting(0); $username = $_GET['username'];//获取get请求的方式得到填写的数据 这里$_GET里的参数是要和前端标签中的name属性是保持一致的 $age = $_GET['age']; echo "你的名字:{$username},年龄:{$age}"; //输出内容 复制代码 观察实验结果,当点击按钮,页面会跳到1.get.php页面,把内容输出。并且观察上面的地址栏,会发现我们输入的信息被放在了地址栏上。 这里就要讲一下网络请求方面的知识,当我们输入网址获取内容,整个过程是怎么发生的呢?浏览器又做了什么? 首先要讲一下HTTP协议,虽然表面上我们通过代码来实现了交互,实际上在网络请求的时候内部是通过各种协议达到了想要的结果,这个协议呢就是一种规范,因为网络上存在太多不同类型的东西,要想互相能交流传递就需要一种共同遵守的约定,才能理解。而我们这里就用到了HTTP协议,希望有机会的人已经要去学习一下计算机网络方面的东西,这里推荐一本书《图解HTTP》,是我看过最清晰易懂的书了,其实有一个系列,都可以看看。 所以当我们输入网址的时候,浏览器根据HTTP协议生成一个请求报文发送给服务端,然后服务端收到这个报文就会进行处理然后回应给我们一个响应报文。这两个报文里面含有请求和回应的各种信息。其实从代码角度来看,请求报文是通过前端代码可以设置的,比如何时发送发送给谁,响应报文就是后端代码处理后返回的一个结果。 请求报文里一般包括请求的方法(GRT/POST),请求的URL或传递的数据等。 响应报文里有请求状态码,比如200表示请求成功,还有返回的一些数据等。 具体我们不说太多,可以自己私下多了解,,主要来说的是GET请求方式和POST的不同在请求报文上的体现。 其实整个GET请求过程如下,假设后台语言是PHP。 1 输入用户信息,点击提交,跳到指定的后台的页面. 2 GET方式会把用户输入的数据名称和对应的值以这样的格式(username=value&age=value )串连起来,放在指定的后台页面的地址栏的问号(?)后面。并且把请求数据放到了请求报文里。 3 后台的代码 ,可以通过PHP语言中的$_GET方法,获取到请求报文的用户信息,用$_GET['username']; $_GET['age']方法获取到值;然后就可以进行一系列逻辑处理。 由此,我们可以知道GET方式: 1 把数据名称和对应的值串连(username=value&age=value ),然后把数据放到指定页面的url地址?后面,然后数据会被加入到请求报文中发送给后端。所以我们完全可以在后台页面的地址栏上手动更改信息,相应的请求报文就会发生变化,GET方式请求的信息在请求报文里也看得到,所以get方式是不安全的,一般不用来提交比较敏感数据,大部分是获取数据的时候用。 2 url有长度限制,所以GET请求的方式有数据量限制,每个浏览器都不同,所以不要用这种方式传递过长的数据。不然会被截取,导致传递数据不完整。 3 只能传递字符串类型 因为是用户名是中文的时候,会默认编码了,所以username后面是乱码。 下面来看看POST方式,同样是这样的需求 HTML页面: 1.get.php 复制代码 <?php header('content-type:text/html;charset="utf-8"'); error_reporting(0); $username = $_POST['username'];//不同的请求方式方法不同,$_POST方法专门用来获取POST方式请求的数据 $age = $_POST['age']; echo "你的名字:{$username},年龄:{$age}"; 复制代码 我们看到输出信息页面,地址栏上没有用户信息了,我们打开开发者工具,找到网络就可以看到我们的请求报文,点进去就是具体内容,看上面的第二个图,可以看到一些请求信息,有请求的编码格式,还有请求地址等,POST请求的数据实际是在请求报文的实体里进行传递的,所以更安全些,但是我们发现我们通过控制台还是可以看到提交的信息,所以其实它也没有很安全,一般还是要对输入的信息进行加密。 我们看第三张图,可以看到请求的数据,上面的其实是浏览器已经按照某种格式输入的信息,下面的源代码才是实际传递的信息,可以看到串连的格式和GET请求是一样的,用户名后面的乱码是编码了,当传递的是中文的时候,才会进行这样的编码。 由此我们可以知道 Post请求 1 数据的串连格式和Get请求是一样的。 2 通过请求报文的信息,通过浏览器内部传输,不会表现在网址上。 3 传输数据量 Post理论上无限 4 可以传递多种数据类型(文本类型,二进制)。 关于Open方法的第一个参数提交方式就讲到这里,第二个地址先简单了解,下面来看第三个参数关于异步和同步。 同步:就是一种阻塞模式,比如代码var a =1 ; alert(a);这就是一种同步,必须执行了第一种var a =1,你才会弹出a的值。 缺点:一般当你后面的代码需要用到前面的东西的时候 适合用同步,如果两句代码完全无关,那用同步就没有必要了。 异步:就是一种非阻塞模式,最明显的例子,就是定时器,当我们写了一个30s后执行的定时器的时候,在30S内定时器后面的代码是可以执行的,而不是过了30s后面代码才能执行,这就是一种异步。 缺点:当你后面的代码需要用到前面的东西的时候 如果用异步,那么后面的代码会在前面还没加载好就出来,可能会有问题。 解决:当你后面的代码需要用到前面的东西的时候,可以用条件判断来决定这些代码的执行,如果条件达成了就可以执行。 还拿上面的举个栗子 复制代码 var oBtn = document.getElementById('btn'); oBtn.onclick = function(){ var xhr = null; if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ xhr = new ActiveXObject(‘Microsoft.XMLHTTP’); } xhr.open('get','1.txt',true); //设置请求信息 xhr.send();//提交请求 //等待服务器返回内容 这里后面会具体讲,大概就是监听服务器的状态,先简单了解即可 xhr.onreadystatechange = function() { if ( xhr.readyState == 4 ) { //如果内容响应成功,并解析完成 alert( xhr.responseText ); //弹出内容 } } } 复制代码 在上面的代码中xhr.send()提交请求是需要时间的,所以必须要等到一定时间提交成功后,我们后面的才能正确获取到内容,所以这就是后面的代码正确执行,依赖于前面, 但是如果用同步的话,我们后面那些不依赖这些前面代码的代码也没办法执行,体验就不好了,所以我们选择用异步,而对于这些依赖前面代码执行的代码,我们就进行判断 if ( xhr.readyState == 4 )就是判断如果数据响应到了,收到了,再弹出内容。(如果我们不判断,按照异步的原理,就会立马弹出来,获取数据需要时间,因为实际还没获取到数据,所以会弹出空,怕误解,所以这里我再强调下). 复制代码 var oBtn = document.getElementById('btn'); oBtn.onclick = function(){ var xhr = null; if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ xhr = new ActiveXObject(‘Microsoft.XMLHTTP’); } xhr.open('get','1.txt',true); //设置请求信息 xhr.send();//提交请求 //等待服务器返回内容 xhr.onreadystatechange = function() { if ( xhr.readyState == 4 ) { //如果内容响应成功,并解析完成 alert( xhr.responseText ); //弹出内容 } } } 复制代码 下面我们就讲到 ,xhr.send();这一句呢才是真正请求数据的,open方法只是设置了一些请求参数。 现在呢请求递交了,就等服务器回应了,这个时候Ajax的一个属性就要登场了,那就是 responseText ,ajax请求返回的内容都放在了这里面,而且不管你请求的内容是什么,这里存放的都是是字符串类型。 当然我们上文也提到了,要想用异步请求呢,这里需要条件判断才知道服务端对请求的内容是否响应完毕,这个时候另一个属性就要登场了,readyState,他代表着Ajax请求过程的不同的状态,参数如下: 0 (初始化)还没有调用open()方法 1 (载入)已调用send()方法,正在发送请求 2 (载入完成)send()方法完成,已收到全部响应内容 3 (解析)正在解析响应内容(因为收到的内容 并不是人能看懂的内容,所以需要解析) 4 (完成)响应内容解析完成,可以在客户端调用了 由上我们可以得到,在状态2的时候已经回应了请求的内容了,但是这个内容我们人看不懂撒,机器才懂,所以就有3,帮我们解析这个内容,然后解析完成就变成4了,这个时候的内容,咱们前端就可以用了。 状态是有了,可咱们怎么能知道啥时候是啥状态呢,这个时候我们就要用到一个监控状态的事件了onreadystatechange事件,当状态值改变的时候触发会触发这个事件,所以当状态为4的时候我们再弹出内容。 上面的代码基本已经了解了原理,不过当然不是最完善的,这个时候,我们虽然监控到了状态,响应了内容,但是内容不一定就是对的呀,比如可能内容出错了,可能我们请求了一个不存在的页面,这个时候readyState是无法判断错误的,我们需要知道内容是否正常,这个时候另一个属性 status属性就登场了,它代表的不是Ajax状态,而是服务器(请求资源)的状态, http状态码。状态码有很多,其中比较出名的就是200,成功状态码,和404 Not Found.其他的大家私下自行查阅。这里可以看到。 所以我们的代码要做进一步的改进 复制代码 var oBtn = document.getElementById('btn'); oBtn.onclick = function(){ var xhr = null; if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ xhr = new ActiveXObject('Microsoft.XMLHTTP'); } xhr.open('get','1.txt',true); //设置请求信息 xhr.send();//提交请求 //等待服务器返回内容 xhr.onreadystatechange = function() { if ( xhr.readyState == 4 ) { if(xhr.status == 200) {//如果响应成功,并且服务器相应内容正确 alert( xhr.responseText );//弹出内容 }else{alert('出错了' + xhr.status); //否则告知出错并弹出错误原因 } } } 复制代码 Ajax的大概流程就是这样的。当然还存在一些细节方面的问题需要注意的,继续往下看把。 GET请求: 1 可能存在缓存问题:后台更改了 因网址未变 所以会去缓存提取内容 而不是后台 来看个栗子:假如我们要点击按钮弹出名字和年龄,因为GET请求是通过数值串连然后在网址传递数据的,所以我们的open方法可以直接这样写: xhr.open('get','1.get.php?username=沐晴&age=21',true); 后台代码不变 复制代码 <?php header('content-type:text/html;charset="utf-8"'); //设置编码格式,以及文档类型 error_reporting(0); $username = $_GET['username'];//获取get请求方式的数据 $age = $_GET['age']; echo "你的名字:{$username},年龄:{$age}"; //输出内容 复制代码 复制代码 现在点击肯定会弹出你的名字沐晴,年龄21 了。 这个时候呢,浏览器会有一个缓存,如果下次访问相同的网址,就会从缓存里取。 比如我现在想弹出,欢迎你,你的名字沐晴,年龄21, echo "欢迎,你的名字:{$username},年龄:{$age}"; //输出内容 虽然后台代码变了,但是GET请求访问网址依然是 1.get.php?username=沐晴&age=21,所以后台会去浏览器缓存找,结果弹出的还是原来的。大家可以自行测试。 所以,这个时候我们需要解决缓存问题。既然访问网址不变的话会去找缓存,那么我们让网址一直变不就好了。所以我们可以在后面加个一直变化的变量,比如系统事件,或者加一个随机数都行,像下面这样: xhr.open('get','1.get.php?username=沐晴&age=21&'+new.Date.getTime(),true); 这样就不会存在缓存问题了。有些人会这样写,会在后面给它起个名字t,这个时候如果后台也有个变量叫t,可能就会出问题了,所以不是很推荐。 xhr.open('get','1.get.php?username=沐晴&age=21&t='+new.Date.getTime(),true); post 请求 1 Ajax中post 数据放在send里面作为参数传递。 2 我们上次我们知道表单里面的第三个参数:enctype: 提交的数据格式,默认是application/x-www-form-urlencoded,但是在Ajax中,你不写就没有,没有默认值,所以我们需要在请求头里面指定提交的数据格式,不然浏览器不知道用哪种格式解析。 所以post请求需要设置下面这两句 1 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); 2 xhr.send('username=沐晴&age=21'); 3 无缓存问题,因为单单是往服务器提交数据,提交数据是不会被缓存的,获取数据才会被缓存。这就是web的机制。 前面讲的都是请求数据,现在来看一下后端接收请求,然后响应给我们的内容。 先看看后端对数据的处理:后端的数据类型也是很多的,我们不能直接把这样的数据给前端吧,所以后端也需要做一定的处理,它有个方法 json_encode 可以根据数据类型不同,然后输出不同格式。看下面的栗子 复制代码 <?php header('content-type:text/html;charset="utf-8"'); error_reporting(0); $arr1 = array('le','mo'); // 索引类型的数据 $arr2 = array('username'=>'le','age'=>32); // 2 对应关系的数据 echo json_encode($arr1); // ["le","mo"] 索引类型 输出为数组格式 echo json_encode($arr2); // {"username":"le","age":32} 对应关系的数据 输出为json格式 复制代码 虽然后端输出的内容格式上是数组和json但是我之前提到过 alert( xhr.responseText );//这里弹出的可都是字符串类型,所以尽管格式上看着是json和数组,但实际的数据类型还是字符串。 所以我们前端要对这些字符串进行转换。这个时候就用到了两个方法 1 stringify() : 把json对象转化成字符串 转换后的字符串是严格的json格式 2 parse() : 把字符串转成对象,可以把后端返回的字符串 转成JSON格式,对于json,只能转换严格json格式的字符串,字符串的键 比较用双引号括起来 像这样 {"username":"le","age":32} 下面来看个实际的案例: 需求:点击页面按钮,实现页面不刷新,在下面显示新闻列表 看注释应该能看懂 复制代码