一.认识Aajx
重要程度:*****
1.什么是Ajax
怎么读?
中文化:阿贾克斯
Ajax:Asynchronous javascript and xml,异步的js和xml。
是指一种创建交互式网页应用的网页开发技术。
Ajax,不是一个语言。是一系列技术的综合应用,(老技术,新应用)。
包括如下技术:
Html
Css
JavaScript
XMLHttpRequest对象(核心)
服务器端语言(node.js和php)
数据库(mysql和mongodb)
所谓的交互式,通常就是指 异步刷新(局部刷新)
2.为什么需要Ajax
为何需要?
从需求出发(平常使用软件出发)。
提到软件,有两种形式:
C/S,client/server,桌面应用程序,QQ,杀毒工具、播放器、编辑器
B/S,browser/server,web应用程序,通过浏览器去访问的web应用
C/S和B/S有何不同之处?
C/S模式,需要在每个用户的电脑安装客户端,后期的更新是比较麻烦的。胖客户端,瘦服务端。
B/S模式,只需要有浏览器即可,更新非常方便。瘦客户端,胖服务端。
由于C/S模式,是在本地安装了一个客户端程序,实现整个软件的部分功能,有很多的功能都是在客户端可以完成的,用户的操作就非常的流畅。
B/S模式,所有的功能都是在服务端实现的,每一次操作都要在服务器进行,都需要一次请求和回应,用户的操作比较卡顿。
但是,随着互联网的发展,越来越多的应用都会使用B/S模式。
矛盾:B/S模式的大量增长和用户体验。
希望,使用B/S模式的架构,同时又具备C/S模式的用户体验。
Ajax就应运而生。在B/S架构的web应用中,获得C/S模式的用户体验。
Ajax 尝试在web应用程序中实现类似c/s应用程序中的功能和交互性,使之能够快速响应用户的操作,从而提高用户体验。
Ajax到底能干什么?
表单交互
动态标签页
及时编辑(云笔记,office在线)
地图类应用
尤其是移动web中更为突出。
3.Ajax的发展历程
实际上,Ajax发展经历了三个时代
Ajax前传,使用iframe实现局部刷新技术
Ajax正传,传统的Ajax
Ajax新传,下一代Ajax,反向Ajax
重要的节点:
同年,Google在三大产品中使用了Ajax技术:
Google Suggest
Google Maps
Gmail
请问:ajax是前端来写的,还是后台来写的?
Ajax是一个老技术的综合应用:
Html
Css
Javasccirpt
Dom
XmlHttpRequest
服务端语言
数据库
任何一个后台开发人员都会写。
在开发中,ajax应该更偏向于前端。前端的代码会多一些。
二.传统的Ajax
Ajax经历了三个时代:
早期,使用iframe来实现的,这种方式功能太弱,已经很少使用了。(可以忽略)
传统,从05年开始一直在使用的。(重点)
反向ajax
1.核心—XMLHttpRequest对象
Ajax是一些来技术的新应用。
涉及了:
浏览器端:HTML、css、js、dom
服务端:后台语言,数据库
每一次都是一个新的请求,会刷新整个页面。
需要开个后门,然后悄悄的发请求,悄悄的返回响应,如下:
这个对象就是XMLHttpRequest了。它是这个ajax中的核心。简称为XHR对象。
直观感受,就是一个js中的对象。
查看如下:
通用定义
XMLHttpRequest是一套可以在Javascript、VbScript、Jscript等脚本语言中通过http协议传送或从接收XML及其他数据的一套API。
来自MSDN的解释
XMLHttpRequest提供客户端同http服务器通讯的协议。客户端可以通过该对象向http服务器发送请求并使用XML文档对象模型处理回应。
我们的理解:
XMLHttpRequest是一个对象,这个对象有属性和方法。我们可以利用这个对象的方法从客户端向服务端发出请求,然后就接受从服务端返回的响应,进行的相应处理。
重点,就是要学习xhr对象到底有哪些属性和方法,以及如何使用的。
参考手册,也就10来个:
2.快速入门案例
(1).目标
需求:在用户注册时,检查这个用户名是否可用。
(2).传统的做法
需要准备一个用户注册界面
使用express来快速提供一个http服务,实现注册功能。
使用express快速编写一个js代码,如下:
对应的reg.html页面如下:
当用户填写完表单,然后进行提交,我们需要去判断用户名是否可用。
需要处理表单提交的post请求。
对应的,定义的inArray函数如下:
访问如下:
还需要返回重新进行注册
这样的用户体验就是非常糟糕的。早期(10年前),这种表单随处可见。
Why?
由http协议本身和代码的实现息息相关的。
http协议,
浏览器发请求
服务端接受请求,进行处理,返回响应。
关键在于响应,使用res写会的响应,就是一个完整的页面。浏览器端接受的就是新的页面,所以原来的页面就不在了。
刚才注册的过程,其实是两次完整的请求和响应。
第一次
第二次
(3).使用ajax来实现用户名检测
使用步骤:
实例化XHR对象
连接服务器
发送请求
接受响应
第一步,实例化xhr对象
在何时,发出请求?
当用户输完用户名之后,就需要检测,使用到失去焦点事件 – blur。
首先,就需要注册blur事件,如下:
在这个blur事件触发的时候,需要实例化对象,发出请求。
第二步,建立和服务器之间的连接
使用xhr对象的open方法,
其中第一个参数为请求方式,如get或者post
第二个参数,表示请求的url,可以使用查询字符串携带参数。
可以编写代码如下:
第三步,注册事件,监听状态的变化
在发出请求之后,需要进行状态的监听,由于这是一个事件,需要在发出请求之前先注册。
注意,事件是全小写的,和onclick、onmouseover对比。
编写代码如下:
第四步,发请求
对应的,需要在服务端编写 /check方法,如下:
运行,测试,看返回的响应是什么?
现在,只需要将 返回的信息,写回到 文本框的后面即可。
编写代码如下:
再次测试。
(4).小结
Ajax,是一个老技术的综合应用。
在刚才的案例中,涉及到如下技术:
浏览器端:HTML,CSS,JavaScript,DOM,XMLHttpRequest对象
服务器端:node.js ,数据库
使用ajax达到了一个什么样的目的?
通过ajax实现了异步请求,在表单还没有提及的情况下,已经发出一个请求,然后判断用户是否可用,从而提高用户体验。
可用使用network工具查看过程
这个过程,对普通用户来讲,是感受不到。
可用使用这种方式,去查看其它web中的ajax请求。如下:
接下来我们的重点,就是要掌握ajax请求和响应整个的过程和细节。
3.创建兼容性的XHR对象
XHR对象,XMLHttpRequest对象。是整个ajax中的核心。
这个对象是如何创建的呢?
分两种情况:
标准浏览器
非标准浏览器(IE)
标准浏览器的创建方式,直接使用new XMLHttpRequest
IE浏览器
ie10以下就存在问题。ie10及其以上已经向标准靠拢。
在ie浏览器中,使用activeXObject对象的方式。
var xhr = new ActiveXObject(“Microsoft.XMLHTTP”); //最原始方式 ie5/ie6
var xhr = new ActiveXObject(“Msxml2.XMLHTTP”); //升级 ie7及以上
注意测试方式。
需要使用ie浏览器测试。此处,使用ietester测试不准确。
需求:如何创建一个兼容性的xhr对象?
用到了try—catch,优雅的处理错误的一种写法。
如果使用jQuery,就不需要自己去做这件事情。
中午:把用户名检测的案例敲一遍。
4.请求方式(get和post)
(1).Get和post 的区别
当实例化好这个xhr对象之后,接下来就需要建立和服务器的连接。
建立连接,就需要使用xhr对象的open方法。
重点就是第一个参数。
第二个参数会随着第一个参数的变化而变化。
第一个参数,表示发起请求的方式。一般就是get和post。大小写均可。
此处的get和post对应于我们http协议中的get请求和post请求。
在原来的http协议中,我们说get请求通常表现为,直接使用url地址,一些标签的src属性和href属性等。而post通常是针对表单。
现在我们还有一种方式,可以发起get和post请求。就是通过xhr对象。
Get和post请求的区别
Post数据,以xml的形式,在http协议做了一些处理,如下:
(2).Get请求
格式:xhr.open(“get”,url)
第一个参数,为get或GET,表示发起了一个get请求
第二个参数,url,
只要是请求,通常是需要携带参数。以查询字符串的方式来传递。所以通常会在url上使用查询字符串。
数据已经通过查询字符串传递过去。
这意味着,我们在后面真正发请求那个动作时,是不需要再发送任何的数据。也就是说xhr.send()方法不需要写任何的内容。通常使用null来作为send方法的参数。
如果有多个键值对,使用&连接即可,如下:
在使用get的时候,有一个细节:
用户填写的内容,如果包含中文(针对ie)、=、&等特殊符号需要编码处理
由于= 和 & 是特殊的,查询字符串中的固定方式。
比如:在用户名中使用了& 和 =,如下:
这就出问题了。
包括,在ie浏览器中,如果使用中文,出现乱码。
针对这些特殊的字符,需要进行编码。 encodeURIComponent
使用如下:
检测,
注意:
编码码之后,不需要解码,因为浏览器会自动进行解码
url编码,其格式为 %十六进制数字 如%20表示空格
在ie浏览器,如果没有进行编码,中文会以乱码来显示
(3).Post请求
在ajax应用中,以get居多(90%以上)。Post请求相对较少。
格式,需要结合项目三个方法
xhr.open(“post”,url)
xhr.setRequestHeader(“content-type”,“application/x-www-form-urlencoded”);
xhr.send(键值对)
编写代码如下:
对应的url处理如下:
查看传递数据的过程
如果没有设置请求头,那么请求的过程是这个样子的,
同理,在使用post的时候,也是需要对特殊的字符进行处理。
&
=
如果没有进行编码,如下:
使用编码之后,
5.异步原理
Ajax中的A,表示Asynchronous,就是异步的意思。
我们在讨论ajax的时候,经常会提到一些说法,异步请求,异步刷新。
异步和同步是对应的。
同步,代码执行的顺序和书写的顺序是一致的。
异步,代码执行的顺序和书写的顺序是不一致的。
同步:提交请求->等待服务器处理->处理完毕返回 等待的过程
异步:请求通过事件触发->服务器处理->处理完毕 没有等待过程
Ajax提供了一个参数,可以设置是使用同步还是异步。
在open方法中,可以通过第三个参数设置。
做一个测试。需要使用firefox来进行测试
增加代码如下:
在服务端,增加一个耗时的操作,
测试,结果如下:
点击确定之后,
如果我们使用同步,会怎么样?
只需要将open方法的第三个参数设置为false,即可。
测试,发现alert直到 请求结果回来之后,才弹出。
在使用ajax,到底是使用同步呢,还是使用异步呢?
视情况而定。但是大部分(90%)都会使用异步。这也是open默认的方式。
如果我后续代码,必须要依赖于请求返回的结果,就应该使用同步。
如:使用ajax请求了jQuery,后面使用jQuery来进行操作。
6.状态说明
在注册事件中,我们编写了如下代码:
这段代码如何理解。
onreadystatechange是xhr的属性,意思就是注册readystatechange事件。
和打电话对比,监听对方的回应。
在事件处理函数中,有两个判断
xhr.status == 200
xhr.readyState == 4
这两个判断是什么意思,能不能不写?
关键在于,在于readyState和status这两个属性的理解。
readyState
当请求发出之后,服务端处理请求,到底是在哪一个环节。
从发出请求开始,到接受数据,到返回响应,定义了如下几个状态:
添加如下测试代码:
只要当所有的数据在浏览器端接受完毕并且解析完成,我们才能使用。
所以,需要进行一个判断,
Status
http响应的状态码。
200表示,正确的接收到服务端的响应数据。
增加这个判断,保证逻辑的正确性。
7.返回数据的方式
当我们从服务器正确接收到返回数据并格式化之后。
也就是说,满足如下条件时
如何接受返回的结果呢?
根据返回的结果的格式的,不同,可以分为两大类:
XML格式,xhr.responseXML
文本格式,xhr.responseText
Ajax,asynchronous JavaScript and xml。此处的X就是指XML。
XML:eXtensible Markup Language,可扩展标记语言
XHTML其实就是XML的一个特例。
XML就是标签语法,和XHTML中的语法是一致的。
在XML中,没有预定义标签。所有的标签都需要自己来定义。
andy
10
由于XML格式,处理起来非常麻烦,数据量也比较大,很少在使用。已经被更轻量的json格式所取代。
不需要用这个XML格式。
我们应该把重点放在文本格式上。
文本格式,就使用responseText表示,如下:
文本,针对不同的格式,有不同的处理方式,可以分为如下三种情况:
纯文本
带有HTML标签的字符串
Json格式的字符串
(1).纯文本
在返回的使用,内容就是纯在字符串。
也可以使用0和1这样的数字字符串。
对应的,返回如下:
(2).带有HTML标签的字符串
可以返回带有HTML标签的字符串,如下:
效果如下:
(3).json格式字符串— 重点
Json已经成为一个最常用的数据交换格式。
我们在web开发时,98%以上都是使用json格式来进行传输。
在服务端,可以返回一个 json格式的字符串。
在客户端,接受,查看这个结果
我们就可以使用 JSON对象的parse方法,将其转成对象,如下:
再次,测试,结果如下:
关于服务端返回json格式的字符串,在express中,还可以直接使用一个res.json方法。
8.案例 - 省市区三级联动
(1).目标
效果如下:
(2).分析
在默认情况下,省份中已经加载数据,市区和区县是空的。
当我们选择了一个省份,对应省份的市区,就会填充数据,区县仍然是空的。
当我们选择了一个市区,对应的区县,就会填充数据。
如果已经选择了一个省份,切换省份,对应省份的市区,就会填充数据,对应的区县应该清空。
在选择省市区的时候,整个页面并没有刷新。此处,就是ajax来实现。
那么,我们的省市区数据,保存在什么地方呢?
首选,就是数据库。
有一些数据,比较特殊,有如下特性:
数据量比较小
数据是固定不变的
针对这种类型的数据,可以使用数据库来保存。还有一种方案,使用json来保存。
此处的省市区数据,也是使用json文件来保存的。
何时请求这些数据的?
省份数据,在页面载入的时候,就已经请求回来了
市区数据,在省份对应的下拉列表触发change事件的时候,请求数据
区县数据,在市区对应的下拉列表触发change事件的时候,请求数据
(3).Ajax获取省份
第一步,需要编写一个server,提供http服务,显示页面
对应的city.html如下:
第二步,请求省份数据
使用ajax来发出请求。
在city.html中,编写js代码如下:
第三步,需要编写服务端的代码,实现对/province的路由
可以使用require直接将json作为模块,获取数据,得到的是一个对象。
只需要进行遍历,如下:
需要将这个数据以json的格式返回个浏览器端。
第四步,在浏览器端,先查看返回的结果
结果如下:
现在,只需要,将返回的结果,做html的拼接,然后写回到select中。其实就是DOM操作。
查看效果如下:
至此获取省份的功能已经实现。
作业:
使用传统方式实现用户名检测
使用ajax方式实现用户名检测
省市区三级联动功能实现
(4).获取对应省份的市区
当我们选择了了一个省份,就应该将其对应的所有市区列出来。
触发条件:切换了一个省份,对应到select的change事件。
需要在触发change事件的时候,使用xhr对象发出ajax请求,并携带当前省份,然后去获取该省份对应的所有市区。
第一步,注册事件,发起请求
在city.html中,注册事件,如下:
先测试
第二步,编写服务端的路由处理
测试,效果如下:
第三步,输出市区列表
在city.html中,编写js代码如下:
测试ok。
(5).获取对应市区的区县
第一步,注册change事件,发请求
编写代码如下:
第二步,在服务端实现路由
编写如下:
测试,如下:
第三步,输出区县信息
在city.html中,输出如下:
测试ok。
整个功能开发完毕,需要整体测试一下。
如果,我们选择的北京,然后选择东城区,发现出错了,如下:
查看错误信息
意思:不能在undefined上面使用forEach,说明调用forEach那个变量是undefined。
分析代码,
说明,在此处,不能直接使用item1.s,如果item1.s存在,才能使用。
测试,ok。
继续测试,
当我们选择了一个市区之后,三级的区县会显示出来,然后我们再次选择某一个省份,区县数据没有变。
在哪儿解决?
在选择省份的时候,才会出现这种情况。需要在这个地方,change事件触发的时候清空区县列表。
测试,ok。
最后,再次查看浏览器端的代码,发现有很多重复的代码。
大家可以使用封装的思想优化一下。
三.jQuery中的ajax
回顾一下,我们在前面使用原生的方式来实现ajax有哪些问题?
代码量较多,有大量的属性和方法需要记住。
兼容性有问题,创建xhr对象
针对特殊的字符串(&、=和中文[ie]),需要进行编码处理
功能相对来说,还不够强大
针对这种情况,几乎所有的基于js的一些框架(库)都实现ajax。
比较突出的就是jQuery。
1. . g e t ( ) 和 .get()和 .get()和.post()
$.get():使用get方式进行ajax请求
$.post():使用post方式进行ajax请求
他们都是$的静态方法。
格式如下:
$.get( url, [data], [callback] ,type),GET方式异步请求
$.post( url, [data], [callback] ,type),POST方式异步请求
data可以是字符串(查询字符串格式),也可以说对象,建议使用对象。
回调函数,表示成功时,要执行的代码,返回结果作为该函数的参数。
type,返回数据的格式,xml、html、script、json、jsonp、text。(自行设定)
使用步骤:
第一步,准备表单页面
第二步,提供一个服务端
第三步,引入jquery
在当前目录,新建一个public目录,将jquery放到该目录下的js目录中,如下:
试图直接,引入jquery,如下:
发现出错了,
查看其路由
相当于请求了publicxxxxxx 路由,但是我们并没有处理它。
需要让其能载入js代码,其实就是静态资源。
我们可以使用express自带的static中间件进行静态资源的托管。在服务端增加代码如下:
在html中,将public目录作为基准目录,写上/开头的路径,如下:
理解的时候,可以将这个/当做是设置好的public目录。
再次,查看如下:
在html中,使用$.get方法实现ajax,编写代码如下:
对应的服务端的代码如下:
测试,
查看network面板,
充分说明,在发请求的时候,将我们的url参数和data参数,做了一个拼接处理,形成一个完整的url。
注意细节:
get和post这两个方法名,必须是小写。 . G E T 或 .GET或 .GET或.POST就要问题。
get和post是作为 $对象的方法,js中是区分大小的。
Type可以指定返回数据的类型,尤其要注意json。
使用如下:
在服务端,返回json格式的字符串
在浏览器端,需要设置返回的类型,如下:
查看效果如下:
说明,已经将这个json格式的字符串转成对象了。直接使用即可。
. p o s t ( ) 使 用 p o s t 的 方 式 实 现 a j a x 请 求 。 用 法 和 .post() 使用post的方式实现ajax请求。用法和 .post()使用post的方式实现ajax请求。用法和.get()一模一样。
浏览器端实现如下:
服务端实现如下:
查看network,如下:
2. . a j a x ( ) 针 对 简 单 的 a j a x 应 用 , 直 接 使 用 .ajax() 针对简单的ajax应用,直接使用 .ajax()针对简单的ajax应用,直接使用.get和$.post就可以完成。
但是,针对一些复杂的需求,就需要使用功能更为强大的 $.ajax()
Ajax也是$对象的静态方法。
使用有两种格式:
用法一:KaTeX parse error: Unexpected character: '' at position 25: …settings ] ] ) ̲ 用法二:.ajax( url [, settings ] ] ) 1.5新增
在ajax方法中,参数有如下:
url,请求的目标URL,默认为当前页面
async,是否是异步请求,默认为true,异步
type,请求类型,可以为POST或GET,默认为GET
data,发送到服务器的数据,可以是字符串或对象类型
dataType,指定返回数据类型xml/html/script/json/text/jsonp
success,指定请求成功后执行的回调函数。
error,请求失败时执行的回调函数
timeout,设置请求超时的毫秒值
Settings这个参数是一个对象,里面的值就是键值对。键名是固定的,就是上面这些。
使用$.ajax来实现get方式的ajax请求,如下:
使用$.post方法实现ajax请求,如下:
请问: . a j a x 、 .ajax、 .ajax、.get和$post有什么关系呢?
实际上, . a j a x 是 整 个 j q u e r y 中 针 对 a j a x 的 核 心 方 法 。 其 他 的 一 些 方 法 , 都 是 基 于 .ajax是整个jquery中针对ajax的核心方法。 其他的一些方法,都是基于 .ajax是整个jquery中针对ajax的核心方法。其他的一些方法,都是基于.ajax方法。
由于get和post这种ajax请求特别常用,所以就创建了两个快捷方法–$.get() 和 $.post()。
$.get()是如下设置的一个快捷方式
$.post()是如下设置的一个快捷方式
3.仿google sugget – 综合案例
(1).目标
(2).分析
肯定是使用ajax来实现的。
Html、css、js、dom
XMLHttpRequest
Node.js
Mongodb
正则表达式
(3).准备工作
数据库准备
准备的数据如下:
如下:
编写html页面,如下:
提供一个http服务,编写服务端代码如下:
启动服务,访问首页面,如下:
(4).具体实现
第一步,引入jquery
第二步,注册事件,发送请求
当我们在文本框中输入一个字符的时候,就需要发送请求。对应什么事件?
input和keyup。
第三步,需要处理ajax请求
先实现精确查询,在服务端编写代码,
测试,如下:
第四步,需要实现模糊查询
当前,我们是一个精确查询。实际上,我们应该进行模糊查询。
肯定要使用正则表达式。有如下两个方案:
先把所有的数据取回来,然后再进行正则匹配
在对数据库进行查询的时候,就使用正则进行匹配
此处,我们使用第二种。
在mongodb中,我们可以使用正则查询。
定义正则并使用,如下:
第五步,在浏览器端输出匹配的列表
效果如下:
可以关掉自动完成功能。
针对为空的情况,需要增加一个判断,如下:
综合运用了前面所学的这些知识,完成了这个应用。综合性非常强,值得拥有。
四.分页的进化史
先体验一下分页的进化史
准备数据,使用json文件来保存我们的数据。
Blog.json
文件内容如下:(主要看格式)
1.不分页
思路:在服务端编写代码,获取blog数据,渲染到模板页面上。
第一步,实现服务端的代码如下:
需要使用ejs模板,安装ejs模板
npm install ejs
然后编写代码如下:
对应的视图页面,如下:
在express中使用ejs模板,注意点:
必须要引入ejs模板
设置模板引擎为ejs
这是view engine为ejs,就意味着我们的模板页面的后缀必须是.ejs。
在使用render方法渲染模板的时候,不要写后缀
访问如下:
在blog.ejs中使用模板语法,输出如下:
稍微加点样式,如下:
结果如下:
2.传统分页
对当前这个博客列表,需要进行分页。
分页原理是什么呢?
何为分页?
当前有21条博客,比如每一页显示5条。
总的记录数total,每一页显示的条数pagesize,
当前所在的页数current表示
数组中有一个方法 slice(start,end),包括start不包括end。
用slice模拟分页取数据的过程。
第一页:1~5 slice(0,5)
第二页:6~10,slice(5,10)
第三页:11~15,slice(10,15)
第四页:16~20,slice(15,20)
第五页:21~25,slice(20,25)
…
第n页:slice((current-1)*pagesize,(current-1)*pagesize+pagesize)
start = (current-1)*pagesize
end = start + pagesize
如何获取每一页的数据
问题:如何知道当前是第几页?
查看京东的列表页,点击下一页,观察url,如下:
其实,就是url后面加查询字符串。
我们可以以如下的url来访问:
http://localhost:4000/blog?page=1
http://localhost:4000/blog?page=2
http://localhost:4000/blog?page=3
http://localhost:4000/blog?page=4
如果给出上述url,就应该返回对应的那一页数据。
编写代码如下:
在地址栏中输入url,进行测试,如下:
这个效果,只能说是实现了手动输入url,获取数据,实际上,我们需要提供一个分页的操作,比如京东,
说明,我们还需要在页面中,加一个分页的超链接。
设计如下:
一共有x条,每页显示y条,当前m/n,上一页 下一页
先在模板页面中,输出上述信息(先死后活),如下:
显示如下:
现在,需要变活。
所以,需要在服务端,获取这些数据,然后在调用render的时候,传入,如下:
对应,在模板页面中,输出即可,如下:
查看效果如下:
然后,就需要使用上一页和下一页的超链接。
需要在上一页/下一页中,写上href属性,属性值为
/blog?page=1
/blog?page=2
/blog?page=3
但是,page的值不是死的,是活的,需要计算。
简单实现如下:
测试,发现可以使用,但是对于临界点有问题,需要判断。
完善,最后一点。
默认进入列表页,没有数据
在获取分页参数的时候,增加一个判断,如下:
3.Ajax简单分页
(1).分析
问题:传统的分页痛点在哪儿呢?
在刚才的页面中,增加一些新的内容,如下:
…
如果页面内容比较多,使用传统分页,每一次都是一个全新的请求,整个页面就会刷新一次。
导致用户体验不好,浪费资源。
需要针对这种情况的应用,使用ajax分页来改造。
如何实现呢?
基本思路,第一次加载页面时,使用ajax方式请求第一页数据。然后提供一个分页的操作。
当我们点击上一页和下一页,需要使用ajax的方式,获取数据,然后写回到页面。
和传统的分页有哪些不同呢?
传统方式,是在服务端返回数据,在浏览器端使用ejs语法输出这些数据。
Ajax方式,在浏览器接受ajax请求的返回值之后,使用dom操作即可。这意味着我们不需要使用ejs模板了。
(2).实现
第一步,编写html代码如下:
第二步,编写服务端代码
启动服务,浏览如下:
第三步,引入jquery,发起ajax请求
在html中,引入jquery,编写js代码如下:
第四步,需要在服务端编写代码,处理请求
重新启动,浏览页面,查看效果,如下:
第五步,在html页面中,进行dom操作,写数据
首先,将博客内容,写会到页面,如下:
查看效果如下:
其次,需要提供分页信息及操作,如下:
测试,如下:
第六步,点击上一页/下一页,需要发起ajax请求,获取数据
这儿有超链接,
但是不是直接,点击,然后跳转。
而是在点击的时候(click事件),使用xhr对象ajax请求。
实现如下:
测试,可以使用。
提示:此处写的不太好,大家先尝试着改造一下。
任务:
省市区三级联动
仿google suggest
分页(传统分页,ajax基本分页)
解决一个小问题:
发现有如下问题:
第一次点击才会生效,后续的点击是没有效果的。
这还是在ajax使用同步的情况。
如果是使用异步,一次点击都不会生效。
需要找寻原因?
DOM中的事件机制有关系。
原来的事件绑定都是基于这个元素本身是已经存在文档当中的。
在此处,我们的事件源是通过js动态添加上去的。而且是每一次ajax请求成功时,都添加了一次。
针对未来的元素进行事件绑定,使用on是不起作用的。
为什么,我使用同步的ajax请求,它就能执行一次呢?
和异步的特点有关系。如果 是异步请求,先绑定事件,后动态写超链接。
如果是同步请求,先动态写超链接,然后是绑定事件。
针对这个情况,需要处理?
使用委托
不要动态的写整个字符串,而是针对数据进行动态设置
第一个方案:使用委托
delegate,针对未来的元素进行事件绑定
所以,我们可以编写代码如下:
在委托的时候,只要是其祖先元素,都可以。
第二种方案,大家自己来实现一下。
4.Ajax分页之加载更多
(1).分析
越来越多的web采用了这种加载更多的方式。
先查看效果:
默认第一次,加载第一页的内容。
然后点击加载更多的button,载入每一页的内容,但是,这次的分页,不是每次显示当前页的内容,而是以累加的方式来展示。追加的方式。
小结论:加载更多和滚动加载,其本质都是分页。只不过是分页的一种更为高级的展示形式,提供更好的用户体验。
(2).实现
服务端的代码,和前面是一模一样的。
需要在html中,增加一个按钮
第一次,载入该页面的时候,需要发起ajax请求,将数据写入到对应的位置。
封装一个方法,如下:
然后,先调用一次,如下:
测试,ok。
当我们点击 button的时候,需要载入下一页的数据,追加到当前页面。
需要注册click事件。
编写代码如下:
测试,可以实现目标效果。
在真实的网站中,发起请求到返回数据,通常是有时间的。
可以使用循环,模拟这个等待事件。
再次访问,发现有一个等待的过程。
需要给一个状态提示。
在还没有返回数据的时候,需要在button中,提示 玩命加载中…
需要利用ajax方法的一些参数。
使用beforeSend方法,如下:
测试,ok。
如果没有数据了,需要增加一个提示,告诉用户没有数据了。
使用控制台,查看,返回的信息
添加一个判断,如下:
测试,ok。
5.Ajax分页之滚动加载(价值很高)
随着移动互联的发展和普及,如何还是使用点击进行加载的话,这个用户体验就不太好了。
如果可以使用滚动加载的机制,就更加理想了。
(1).分析
关键点:在什么时候发起ajax请求?
当滚动条滚动到页面的底部。
问题来了:如何判断滚动条到底了?
分析,有哪些和高度相关的值,发生了变化,哪些和高度相关的值没有发生变化。
以滚动条作为核心,来分析?
为什么有滚动条?
和高度相关的有如下几个:
滚动条滚动的高度(距离)
页面可视区域的高度
文档内容的高度
在jquery中,如何获取这三个高度呢?
滚动条滚动的高度 — $(window).scrollTop
页面可视区域的高度 — $(window).height
文档内容的高度 — $(document).height
编写简单代码,测试,查看这三个值
测试,查看结果
接下来,需要分析,当满足什么条件时,表示滚动条滚动到底部?
对于上面的这三个高度,需要观察它们的变化。
针对滚动条的高度
在不停的增加。
针对窗口可视区域的高度
基本保持不变,如果把浏览器窗口进行缩放,就会变化。忽略,当做就是不变的。
文档内容的高度
文档内容的高度,一般也是不变的。
滚动条滚动到底部的条件 什么呢?
只需要,滚动滚动条,观察三个值的变化。
2369 + 667 = 3036
条件浮出水面:$(window).scrollTop() + $(window).height() >= ( d o c u m e n t ) . h e i g h t ( ) ( 2 ) . 实 现 根 据 刚 才 的 分 析 , 关 键 点 已 经 找 到 了 。 (document).height() (2).实现 根据刚才的分析,关键点已经找到了。 (document).height()(2).实现根据刚才的分析,关键点已经找到了。(window).scrollTop() + $(window).height() >= $(document).height()
也就是说,需要注册滚动事件,当满足条件,发起ajax请求。
服务端的代码不变。
先准备html页面,如下:
需要注册滚动事件,代码如下:
测试,可以实现滚动加载了。
但是,没有任何的提示信息,不太友好。
需要增加一个提示信息。
准备一张loading动画图片,如下:
在发请求的时候,就需要加载这个图片。在请求成功之后,需要去掉这张图片。
同时,需要在滚动时,进行判断,如下:
测试,ok!
至此,使用ajax滚动加载的效果就已经实现了。
五.跨域(搞定面试官的杀手锏)
如果说ajax是衡量一个前端开发人员水平的一杆秤。
那么跨域则是衡量你掌握ajax的程度。也是能够体现你工作经验的地方。
在不清楚原理的情况,是可以使用的。
用的不好。
1.什么是跨域访问
(1).什么是跨域?
前提:是针对ajax请求的,就会出现跨域问题。
比如,我们通常会使用第三方cdn的js,如下:
跨域是什么意思?
域一般我们是指域名。
它实际上,包括三个部分:
协议:http/https
主机:可以是ip形式,也可以是域名形式,192.168.0.225 www.baidu.com
端口:在主机后使用冒号隔开的那个值。
http://www.baidu.com:80
http://192.168.0.225:3000
什么时候,会发生跨域呢?
当我们去请求一个url的时候,当前页面所在的域和请求的目标url的域是不同的两个域,就是跨域。只要协议、主机和端口有一个不同,那就是跨域。
如:
请求的页面的域:http://192.168.0.225:3000
目标url的域:http://192.168.0.225:4000
我们认为这就跨域了,因为端口不同。
再如:
http://192.168.0.225:3000 – > https://192.168.0.225:3000
http://192.168.0.225:3000 --> http://192.168.0.226:3000
ps:在http/https协议中,如果没有写端口,默认通常就是80端口。
Ps:如果域名和ip是一一对应关系,也认为是不同的两个主机,肯定是跨域。
主域名和子域名(二级域名)的问题
百度的主域名:www.baidu.com
子域名:news.baidu.com/,music.baidu.com
主域名和子域名也是不同的域,肯定是跨域。
(2).同域的ajax请求
编写服务端代码如下:
对应的corss.html如下:
在cross.html中,注册点击事件,发起ajax请求
其中,重点就是url,设置为/ajax,表示当前域下的/ajax路由。
在服务端,需要针对/ajax请求,处理之,编写代码如下:
访问,结果如下:
(3).跨域的ajax请求
准备一个4000端口的服务,如下:
在3000端口服务的html页面中,向4000端口发起了ajax请求,代码如下:
然后,点击按钮,发出请求,结果如下:
不允许访问。这就是跨域了。
图示如下:
2.跨域解决方案
问题:为什么跨域不能访问?
基于安全的考虑,在web中,有一个同源策略。不允许不同域的ajax请求。
但是,我们在实际开发中,跨域这种需求普遍存在的。
此处,介绍三种比较典型的跨域方案:
CORS
jsonp
代理
(1).CORS
Cross Origin Resource Sharing ,跨资源共享。
非常简单的一种方案。
这个方案,可以查看跨域的错误提示:
我们可以在服务端设置,允许别的域使用ajax发起请求。
而浏览器基本没啥事。
只需要设置一些header头,如下:
res.setHeader(‘Access-Control-Allow-Origin’, “*”); //*表示所有域
res.setHeader(‘Access-Control-Allow-Credentials’, true); //跨域时能否使用cookie
res.setHeader(‘Access-Control-Allow-Methods’, ‘POST, GET, PUT, DELETE, OPTIONS’);
在服务端,设置如下:
重启服务,再次测试,如下:
说明跨域成功了。
小结:针对cors方式,只需要在服务端设置相应的响应头信息即可,浏览器不需要任何设置。
(2).Jsonp
a.使用jsonp解决跨域
jsonp是什么意思呢?先放一下。
需要在客户端和服务端同时进行设置。
a.浏览器端,需要设置,以jsonp的方式来返回数据。
查看手册,如下:
浏览器端,只需要设置返回的数据格式为jsonp即可,如下:
对应的,在服务器端,需要使用jsonp的格式来返回数据。
可以查看,发起的ajax请求,如下:
发现,一旦设置了jsonp之后,在url后面增加一个查询字符串callback=jQuery1113xxxxx。
相当于传递了一个回调函数的名字 — jQuery1113xxxxx
它需要,我们在服务端,发回一个字符串数据,返回到浏览器端。执行这个函数。
也就是说,在返回的内容中,需要发回调用函数的一个字符串。将数据作为函数的参数。
测试,效果如下:
所谓的jsonp,json with packing。将json包装起来。
需要有一个函数,然后将真正需要是json数据,作为该函数的参数,包装起来。
Json和jsonp是两个的东西
Json是一种数据格式。情报
Jsonp是以一个协议,使用jsonp这个协议,返回json数据。传送情报的手段
如果我们使用的是express。恰好封装了一个方法—jsonp。
实际上, express中的jsonp方法,就是上述两行代码的封装。
如果从使用的层面来讲,掌握这么多,jsonp就可以使用了。
浏览器端,设置dataType为jsonp
服务端,使用res.jsonp方法返回数据即可
b.深入jsonp原理
先准备server端,代码如下:
对应的cross3.html如下:
问题来了,如何发出一个请求呢?
利用script标签的特点,它可以请求任何域的js代码。
但是,不能写死,只能在点击事件触发的时候,发回发请求。
编写一个js文件, 如下:
可以在头部直接引入,如下:
但是,如此一来,页面一载入,就执行了,不对。
我们需要的是在点击button时,才发请求。
可以动态的增加一个script标签,定义一个函数如下:
在点击button的时候,调用该函数,
测试,点击button,如下:
目前是同域的,换一个域。
在增加一个http服务,如下:
再次访问,查看network,如下:
效果ok,
不想简单的弹出一个alert框,需要获取数据的。
可以直接写上url,如下:
查看请求的情况,如下:
完全没有问题。
相应的,在服务端,编写代码如下:
测试
说明,数据已经返回了。
但是,在浏览器端,没有办法接受这个数据,因为是使用addscript发起的请求,没有回调。
查看结果如下:
问题是,我想输出的是 服务端返回 的数据。
可以在服务端,返回一段js代码,如下:
需要在浏览器中输入url直接访问测试,http://localhost:4000/blog
所以,我就返回函数调用的代码
再次测试,查看效果如下:
对应的输出如下:
还有一个小问题,在服务端,怎么知道你的那个方法名字就是f1呢?如果你改成f2,我就挂了。
在发请求的时候,将函数的名字作为查询字符串传递过去,然后在服务端获取即可。
对应的请求如下:
了解这个原理,才算是真正的掌握了jsonp。
可以回头看看jquery是如何做到的。
Jsonp,json with packing。将要返回的json数据作为函数的参数。返回的是一个函数调用的字符串。
Jsonp是一个协议,不是数据。数据是它的参数。
(3).代理
什么是代理?
proxy,
使用第三方完成这个某个任务,和日常生活中的代理是一样。
什么时候用代理?
如果服务器在别人的手里(我们仅仅能够拿到api,url)。此时,就无法使用jsonp了。
演示:
http://v.juhe.cn/toutiao/index?type=top&key=fdbe4736f44b03fd18310ae63d058e69
编写服务端的代码如下:
编写浏览器端的代码如下:
结果如下:
很明显,又是跨域了,不能跨域访问。
试图使用jsonp来解决这个问题。
结果如下:
悲剧了,出现了语法错误。
原因很简单,就是因为服务端没有使用jsonp的协议返回数据。
现在这个api是别人的,我没有权利去修改人家服务器端的代码。
针对这种情况,jsonp就无能为力。
如何使用代理?
这是刚才的情况,如图:
由于服务端是不在我们的控制范围之内,不能使用cors和jsonp来解决。
需要寻求新的方案。
使用代理就可以实现。
示意图如下:
在域3000下面,定义一个路由,去请求目标域。/proxy
直接使用http://localhost:3000/proxy 访问,如下:
说明,已经拿到数据了。
我们现在使用ajax方式去请求 http://localhost:3000/proxy
对应的html页面中,修改url如下:
服务端,需要返回json数据,如下:
需要发起ajax请求的时候,将目标地址传过去。
服务端,需要获取这个url,如下:
结果如下:
代理模式的关键是 在服务器端发请求,是没有任何限制的。(爬虫正是因此而来)
至此三种方案介绍完毕:
Cors,只需要在服务设置header头信息即可。
Jsonp,讨论得最多的一种,使用比较多一种,需要在客户端使用jsonp的方式(jQuery),服务端需要使用jsonp的协议返回数据
代理,cors和jsonp都无法搞定的情况,可以使用代理。
六.反向Ajax
1.什么是反向ajax?
传统的ajax有何特点,有何痛点?
传统的ajax特点:
对比理解:世上只有藤缠树,人间哪有树缠藤。
说白了,传统的ajax是一个单向的数据传输。
传统的ajax有何痛点?
随着web的发展,在web上需要完成更多的功能。
网页游戏,在线聊天室,客服系统。
浏览器没有发请求,但是服务器端的内容已经发生了变化,对应的我们的浏览器的内容是需要更新的。服务器没有通知浏览器的功能。
2.常见解决方案
针对新的需求,服务器如果有更新,需要及时通知到浏览器端。
HTTP轮询
Comet (长轮询/iframe)
web sockets
轮询的方案,大家了解一下即可。
使用循环,每隔固定的时间,从浏览器端向服务器端发起ajax请求。
轮询是有缺点的:
浪费资源,有很多无用的请求,这些请求不会有新的数据回来
及时性不够,针对实时性要求比较高的应用,就存在问题
需要有一种新的机制。要实现的是双向通信。
在HTML5中,提出了一个web socket的规范。
WebSocket是HTML5的一种新通信协议,它实现了浏览器与服务器之间的双向通信。
有很多种实现方案:
其中,有一个最为著名的方案 – socket.io。
Socket.io是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架,它包括了客户端的JavaScript和服务器端的Node.js。
Socket.io设计的目标是构建能够在不同浏览器和移动设备上良好运行的实时应用,如实时分析系统、二进制流数据处理应用、在线聊天室、在线客服系统、评论系统、WebIM等。
在讲解node.js的时候,node有一个其他任何后台语言都不能比拟的特点 — 构建实时web应用。
3.Socket.io
(1).如何使用socket.io
socket.io 实现了web socket规范,实现了双向通信。
对应的在客户端,需要有一个js文件。
同理,在服务端,也需要有一个模块。
针对服务端的安装。
由于是基于node.js,所以还是将其作为模块来安装使用的,如下:
针对客户端的。
应该去官网下载,http://socket.io/docs/
然后,就是编写代码实现。
第一步,编写服务端代码如下:
第二步,编写html页面如下
然后,可以启动服务,显示这个页面,
第三步,在服务端,实例化io对象,提供监听
实际上,建立socket.io的连接,就相当于在原来的http的连接基础之上,修了一个条秘密通道,如下:
在服务端,编写代码如下:
第四步,在客户端去连接服务端
对应的,需要在服务端,进行静态资源托管,如下:
然后,我们访问,观察服务端和客户端对应的socket对象。
浏览器端,如下:
服务端:
至此,我们已经将这个秘密通道建立好,并且双方都有一个信使(就是socket对象)。
接下来,就需要进行通信了。
任务:
Ajax分页的多种形式,简单的、加载更多、滚动加载
跨域的三种实现,
jsonp的原理,还是要关注一下。