ajax 笔记
前言
我们使用 php 动态渲染页面时,有很多比较麻烦的地方。
- 在前端写好页面以后,需要后台进行修改,意味这后端程序员也需要懂前端的知识,其实渲染的工作应该交给前端来做。
- 前端没有写好页面的话,后端无法开始工作,需要等待前端的页面完成之后才能开始工作,拖延项目的进度。
- 这种渲染,属于同步渲染,先获取数据, 如果数据获取的慢了, 会严重影响整个页面渲染速度, 且数据更新需要页面刷新
AJAX
即 Asynchronous [e’sɪŋkrənəs] Javascript And XML, AJAX 不是一门新的语言,而是对现有技术的综合利用。 本质是在 HTTP 协议的基础上以异步的方式与服务器进行通信
同步与异步
同步和异步概念:
同步:指的就是事情要一件一件做。等做完前一件才能做后一件任务
异步:不受当前任务的影响,两件事情同时进行,做一件事情时,不影响另一件事情的进行
编程中:异步程序代码执行时不会阻塞其它程序代码执行,从而提升整体执行效率
网页异步应用:
- 验证你的用户名是否已经存在(一边输入,一边获取你的信息,和后台比对)。
- 百度搜索提示,及相关内容展示(一边输入,一边找出了你可能要的内容)。
- 新浪微博评论(异步加载)。
XMLHttpRequest 可以以异步方式的请求数据处理程序, 可实现对网页的部分更新, 而不是刷新整个页面
XMLHttpRequest 对象
浏览器内建对象,用于与服务器通信(交换数据) , 由此我们便可实现对网页的部分更新,而不是刷新整个页面。这个请求是异步的,即在往服务器发送请求时,并不会阻碍程序的运行,浏览器会继续渲染后续的结构。
发送 get 请求
XMLHttpRequest 以异步的方式发送 HTTP 请求,因此在发送请求时,一样需要遵循 HTTP 协议。
使用 XMLHttpRequest 发送 get 请求的步骤
// 1. 创建一个 XMLHttpRequest 对象 |
注意点 :
- get 请求,设置请求行时,需要把参数列表拼接到 url 后面
- get 请求不用设置请求头,不用说明请求主体的编码方式
- get 请求的请求体为 null
发送 post 请求
// 1. 创建一个 XMLHttpRequest 对象 |
注意点 :
- post 请求,设置请求行时,不拼接参数列表
- post 必须设置请求头中的 content-type 为
application/x-www-form-urlencoded
, 标记请求体解析方式 - post 请求需要将参数列表设置到请求体中
获取响应 readyState
readyState
:记录了 XMLHttpRequest 对象的当前状态
readyState 有五种可能的值:
- xhr.readyState = 0 时,UNSENT open 尚未调用
- xhr.readyState = 1 时,OPENED open 已调用
- xhr.readyState = 2 时,HEADERS_RECEIVED 接收到头信息
- xhr.readyState = 3 时,LOADING 接收到响应主体
xhr.readyState = 4
时,DONE 响应完成
HTTP 响应分为 3 个部分,状态行、响应头、响应体。
// 给xhr注册一个 onreadystatechange 事件,当 xhr 的状态发生状态发生改变时,会触发这个事件。 |
案例
【判断用户名是否存在】
【用户登录案例】
【聊天机器人案例】
数据交互
浏览器端只是负责用户的交互和数据的收集以及展示,真正的数据都是存储在服务器端的。
我们现在通过 ajax 的确可以返回一些简单的数据(一个字符串),但是在实际开发过程中,肯定会会设计到大量的复杂类型的数据传输,比如数组、对象等,但是每个编程语言的语法都不一样。
因此我们会采用通过的数据交换格式(
XML
、JSON
)来进行数据的交互。
XML(了解即可)
什么是 XML
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
- XML 标签没有被预定义。您需要自行定义标签。
语法规范
- 第一行必须是版本信息
- 必须有一个根元素(有且仅有一个)
- 标签不可有空格、不可以数字或 . 开头、大小写敏感
- 不可交叉嵌套,都是双标签,如果是单标签,必须闭合
- 属性双引号(浏览器自动修正成双引号了)
- 特殊符号要使用实体
- 注释和 HTML 一样
|
php 获取 xml 文件的内容
// 注意: 如果需要返回 xml 数据, 需要将 content-type 改成 text/xml, 不然浏览器以 text/html 解析 |
js 解析 xml
// 获取服务端返回的 xml 数据,需要使用 xhr.responseXML,这是一个 document 对象,可以使用 DOM 中的方法查找元素。 |
缺点:虽然可以描述和传输复杂数据,但是其解析过于复杂, 并且体积较大,所以实现开发已经很少使用了
JSON 数据
JSON
(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript 规范,采用独立于编程语言的文本格式来存储和表示数据
- 数据在键值对中
- 数据由逗号分隔(最后一个 键值对不能带逗号)
- 花括号保存对象,方括号保存数组
- 键和值使用双引号
var obj = { a: 'Hello', b: 'World' } // 这是一个对象 |
JSON 数据在不同语言进行传输时,类型为字符串,不同的语言各自也都对应有解析方法,解析完成后就能很方便的使用了
php 处理 json
- php 关联数组 ==> json ( json_encode )
// php的关联数组 |
- json ==> php 对象/关联数组 ( json_decode )
$json = '{"a": "Hello", "b": "World"}'; // json字符串 |
JS 处理 json
JSON.stringify(obj)
:JS 对象 ==> JSON 字符串
var obj = { a: 'Hello', b: 'World' } |
JSON.parse(obj)
:JSON 字符串 ==> JS 对象
var json = '{"a": "Hello", "b": "World"}' |
【案例:获取表格数据.html】
兼容性处理 (了解, 不用处理)
现在一般最多兼容到 IE8, 这里以后见到了知道是在处理兼容性就行了
var xhr = null |
封装 ajax 工具函数
每次发送 ajax 请求,其实步骤都是一样的,重复了大量代码,我们完全可以封装成一个工具函数
//1. 创建xhr对象 |
参数提取
参数名 | 参数类型 | 描述 | 传值 | 默认值 |
---|---|---|---|---|
type | string | 请求方式 | get/post | 只要不传 post,就是 get |
url | string | 请求地址 | 接口地址 | 如果不传地址,不发送请求 |
async | boolean | 是否异步 | true/fase | 只要不传 false,那就是 true,异步请求 |
data | object | 请求数据 | {key:value,key1:value2} |
需要把这个对象拼接成参数的格式 uname=hucc&upass=12345 |
dataType | string | 返回的数据类型 | xml/json/text | text |
success | function | 响应成功时调用 | - | - |
error | function | 响应失败时调用 | - | - |
参数检测
// 要求参数obj必须传递,否则直接不发送请求 |
完整版本
var $ = { |
【登录案例】
jQuery 中的 ajax 方法
jQuery 为我们提供了更强大的 Ajax 封装
$.ajax
参数列表
参数名称 | 描述 | 取值 | 示例 |
---|---|---|---|
url | 接口地址 | url:”02.php” | |
type | 请求方式 | get/post | type:”get” |
timeout | 超时时间 | 单位毫秒 | timeout:5000 |
dataType | 服务器返回的格式 | json/xml/text(默认) | dataType:”json” |
data | 发送的请求数据 | 对象 | data:{name:”zs”, age:18} |
beforeSend | 调用前的回调函数 | function(){} | beforeSend:function(){ alert(1) } |
success | 成功的回调函数 | function (data) {} | success:function (data) {} |
error | 失败的回调函数 | function (error) {} | error:function(data) {} |
complete | 完成后的回调函数 | function () {} | complete:function () {} |
使用示例:
$.ajax({ |
【案例:登录案例.html】
接口化开发
请求地址即所谓的接口,通常我们所说的接口化开发,其实是指一个接口对应一个功能, 并且严格约束了请求参数 和响应结果 的格式,这样前后端在开发过程中,可以减少不必要的讨论, 从而并行开发,可以极大的提升开发效率,另外一个好处,当网站进行改版后,服务端接口进行调整时,并不影响到前端的功能。
获取短信验证码
【案例:register】
需求文档(产品)
总需求:点击获取验证码按钮,向服务端发送请求, 调用服务器端短信接口, 服务器端根据传参, 调用第三方短信接口, 给手机发送验证码 |
接口文档
接口说明:获取短信验证码 |
注册接口
【案例:register】
表单序列化 serialize
jquery 提供了一个serialize()
方法序列化表单,说白就是将表单中带有 name 属性的所有参数拼成一个格式为name=value&name1=value1
这样的字符串。方便我们获取表单的数据。
// serialize 方法将表单参数序列化成一个字符串。必须指定 name 属性 |
jquery 的 ajax 方法,data 参数能够直接识别表单序列化的数据
$.post({ |
需求文档
注册功能 |
接口文档
接口说明:注册 |
模板引擎
是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的 HTML 文档。
为什么要使用模板引擎
我们通过 ajax 获取到数据后,需要把数据渲染到页面,在学习模板引擎前,我们的做法是大量的拼接字符串,对于结构简单的页面,这么做还行 ,但是如果页面结构很复杂,使用拼串的话代码可阅读性非常的差,而且非常容易出错,后期代码维护也是相当的麻烦。
总结来说拼串渲染两大缺点:
- js 中大量充斥着 html 结构拼串代码, 很冗余,可读性差
- 字符串拼接很麻烦, 且维护起来也很麻烦, 容易出错
常见的模板引擎
BaiduTemplate:http://tangram.baidu.com/BaiduTemplate/
velocity.js:https://github.com/shepherdwind/velocity.js/
ArtTemplate:https://github.com/aui/artTemplate
artTemplate 是使用最广泛,效率最高的模板引擎,需要大家掌握。
artTemplate
github 地址
中文 api 地址
artTemplate 的基本使用
1. 引入模板引擎的 js 文件
<script src='template-web.js'></script> |
2. 准备模板
<!-- |
3. 准备数据
//3. 准备数据,数据是后台获取的,可以随时变化 |
4. 将模板与数据进行绑定
//第一个参数:模板的id |
5. 修改模板
<script type="text/html" id="myTmp"> |
6. 将数据显示到页面
var div = document.querySelector('div') |
artTemplate 标准语法
if 语法
{{if gender='男'}} |
each 语法
<!-- |
//如果返回的数据是个数组,必须使用对象进行包裹,因为在{{}}中只写书写对象的属性。 |
瀑布流案例
封装 jQuery 瀑布流插件
// 特点分析: |
代码参考:
$.fn.waterfall = function() { |
瀑布流完整版
// 需求分析: |
同源与跨域
同源
同源策略的基本概念
1995 年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
同源策略:最初,它的含义是指,A 网页设置的 Cookie,B 网页不能打开,除非这两个网页”同源”。所谓”同源”指的是”三个相同”:协议相同、域名相同、端口相同
同源策略的目的
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
同源策略的限制范围
随着互联网的发展,“同源策略”越来越严格,目前,如果非同源,以下三种行为都将收到限制。
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 无法获得
- AJAX 请求响应被拦截
虽然这些限制是很有必要的,但是也给我们日常开发带来不好的影响。比如实际开发过程中,往往都会把服务器端架设到一台甚至是一个集群的服务器中,把客户端页面放到另外一个单独的服务器。那么这时候就会出现不同源的情况,如果我们知道两个网站都是安全的话,我们是希望两个不同源的网站之间可以相互请求数据的。这就需要使用到 跨域 。
跨域
jsonp( 无兼容性问题 )
JSONP(JSON with Padding)
可用于解决主流浏览器的跨域数据访问的问题。原理:服务端返回一个定义好的 js 函数的调用,并且将服务器的数据以该函数参数的形式传递过来,这个方法需要前后端配合
script
标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件。类似的还有img
和link
标签
jsonp 演化过程 1
php 文件
header("content-type:text/html;charset=utf-8"); |
html 文件
<script src="http://www.api.com/testjs.php"></script> |
原理:其实 src 的路径是什么文件不重要,无论引入 js 文件还是 php 文件,最后返回给浏览器的都是字符串,因此我们 script 标签是可以引入一个 php 文件的。
jsonp 演化过程 2
php 文件
header("content-type:text/html;charset=utf-8"); |
html 文件
<script src="http://www.api.com/testjs.php"></script> |
我们现在做到了一件事情,从不同源的 php 文件中获取到了数据
缺点:获取数据的 script 标签必须写在使用的 script 标签的前面,必须保证先有数据才能对数据进行渲染。
jsonp 演化过程 3
php 代码
header("content-type:text/html;charset=utf-8"); |
js 代码
<script> |
缺点:后端必须知道前端声明的方法的名字,后端才能调用。
jsonp 演化过程 4
php 代码
header("content-type:text/html;charset=utf-8"); |
javascript 代码
function fun(data) { |
- jsonp 的原理就是 借助 script 标签 src 请求资源时,不受同源策略的限制
- 在服务端返回一个函数的调用,将数据作为当前调用函数的实参
- 在浏览器端,声明一个全局函数,通过形参就可以获取到服务端返回的对应的值
jquery 对于 jsonp 的封装
!> jsonp 仅支持 get 请求
// 使用起来相当的简单,跟普通的get请求没有任何的区别,只需要把 dataType 固定成 jsonp 即可 |
XMLHttpRequest2.0
XMLHttpRequest 是一个 javascript 内置对象,使得 Javascript 可以进行异步的 HTTP 通信。2008 年 2 月,就提出了 XMLHttpRequest Level 2 草案。
老版本的 XMLHttpRequest 的缺点:
- 仅支持传输文本数据,无法传输二进制文件,比如图片视频等。
- 传输数据时,没有进度信息,只能提示完成与否。
- 受到了”同源策略”的限制
新版本的功能:
- 可以设置 timeout 超时时间
- 可以使用 formData 对象管理表单数据
- 允许请求不同域名下的数据(跨域)
- 支持上传二进制文件
- 可以获取数据传输的进度信息
注意:我们现在使用 new XMLHttpRequest 创建的对象就是 2.0 对象了,我们之前学的是 1.0 的语法,现在学习一些 2.0 的新特性即可。
timeout 设置超时
xhr.timeout = 3000 // 设置超时时间 |
formData 管理表单数据
formData 对象类似于 jquery 的 serialize 方法,序列化表单,实现表单的异步提交
!> 但 serialize 方法无法实现文件上传
使用:
- 实例化一个 formData 对象, new FormData(form); form 就是表单元素,DOM 对象
- formData 对象可以直接作为 xhr.send(formData) 的参数。注意此时数据是以二进制的形式进行传输。
- formData 有一个 append 方法,可以添加参数。formData.append(“id”, “1111”);
- 这种方式只能以 post 形式传递,不需要设置请求头,浏览器会自动为我们设置一个合适的请求头。
代码示例:
// 1. 使用formData必须发送post请求 |
如果要获取 formData
中的数据,可以使用 formData.get('')
获取
文件上传
以前,文件上传需要借助表单进行上传,但是表单上传是同步的,也就是说文件上传时,页面需要提交和刷新,用户体验不友好,xhr2.0 中的 formData 对象支持文件的异步上传。
var formData = new FormData() |
!> 如果使用 $.ajax
发送 , 需要添加如下两项参数
contentType: false,
设置编码类型
processData: false,
设置传递值方式
显示文件进度信息
xhr2.0 还支持获取上传文件的进度信息,因此我们可以根据进度信息可以实时的显示文件的上传进度。
- 需要注册
xhr.upload.onprogress = function(e){}
事件,用于监听文件上传的进度。注意:需要在 send 之前注册。 - 上传的进度信息会存储事件对象 e 中
e.loaded
表示已上传的大小;e.total
表示整个文件的大小
代码参考:
xhr.upload.onprogress = function(e) { |
默认上传文件限制 8M,需要配置 php.ini,允许 php 上传大文件
跨域资源共享(CORS)
CORS 的使用
新版本的 XMLHttpRequest 对象,可以向不同域名的服务器发出 HTTP 请求。这叫做跨域资源共享(Cross-origin resource sharing,简称 CORS)。
跨域资源共享(CORS)的前提
- 浏览器支持这个功能( 兼容性 IE10+ )
- 服务器必须允许这种跨域
服务器允许跨域的代码:
// 允许所有的域名访问这个接口 |
CORS 的具体流程(了解)
浏览器发送跨域请求
服务器端收到一个跨域请求后,在响应头中添加 Access-Control-Allow-Origin Header 资源权限配置。发送响应
浏览器收到响应后,查看是否设置了
header('Access-Control-Allow-Origin:请求源域名或者*');
如果当前域已经得到授权,则将结果返回给浏览器,否则浏览器忽略此次响应
结论:
- 跨域行为是浏览器行为,响应是回来了, 只是浏览器安全机制做了限制, 对于跨域响应内容进行了忽略。
- 服务器与服务器之间是不存在跨域问题的
jsonp 与 cors 的对比
- jsonp 兼容性好,老版本浏览器也支持,但是 jsonp 仅支持 get 请求,发送的数据量有限,使用麻烦
- cors 需要浏览器支持 cors 功能才行。使用简单,只要服务端设置允许跨域,对于客户端来说,跟普通的 get、post 请求并没有什么区别
- 跨域的安全性问题:因为跨域是需要服务端配合控制的 ,也就是说不论 jsonp 还是 cors,如果没有服务端的允许,浏览器是没法做到跨域的
【案例:图灵机器人】