JavaScript 进阶知识 - Ajax篇

image

Ajax

前言

前面咱们已经学习了js基础知识和一些简单的特效,基本上已经可以写出一个带有特效的静态页面了,为何还要称之为静态页面呢?由于网页里的数据都是写死的,真正的工做中,咱们是要经过Ajax技术,去后台获取数据的。因此在本篇文章,我会向你们介绍下什么是Ajax技术,而且它的实现原理是什么。javascript

1. 服务器端技术基础

1.1 服务器

在学习 Ajax以前,咱们首先须要知道什么是服务器。

一、什么是服务器?php

服务器的本质其实就是一台电脑,不过它不像通常的电脑同样拥有鼠标键、键盘、显示器等输入设备,它直接就是一个主机,里面只有主板、硬盘、 cpu、内存而且性能比通常计算机的性能更高,稳定性更强。
  • 经过网络为其余计算机提供应用服务的计算机就是服务器。
  • 有别于普通的PC,服务器性能更好、安全性更高、稳定性更强。
  • 服务器运行在有特定环境要求的地方
  • IDC(对气候、能源、消防、建筑、安保等要求。

服务器外观图:css

image

image

二、服务器提供什么服务html

根据需求的不一样,服务器的种类也有所不一样。
  • 网页服务器(Web Server)
  • 邮件服务器(Mail Server)
  • 数据库服务器(Database Server)
  • FTP服务器(FTP Server)
  • 域名服务器(DNS Server)

三、服务器操做系统:前端

  • Windows Server
  • LinuxDebianUbuntuCentOSFedora

四、服务器的应用软件:java

  • Web服务器(又称:http服务器,主要提供文档的浏览功能,文本、图片、视频、音频)。mysql

    • IISWindows
    • Apache
    • Nginx
  • 数据库服务器jquery

    • SQL Server
    • Oracle
    • MySQL

1.2 客户端

客户端: 经过网络向服务器请求服务的计算机就是客户端(手机、电脑);web

客户端软件: 在客户端计算机上运行的与服务器通信的软件就叫客户端软件;ajax

单机软件: 在客户端计算机上运行的不访问网络的软件叫作单机软件;

1.3 软件开发架构

软件开发架构分为两种,分别是 C/S架构和 B/S架构。

一、C/S架构:

C/S,是 Client:(客户端)和 Server(服务器)两个单词的简写,指的是客户端应用程序与服务器端应用程序通信的软件开发架构。

对于C/S架构,最为常见的例子就是网络游戏,好比LOL,若是不联网就没法使用。

优势:

  • 因为是原生的应用,因此显示的效果会更加酷炫;
  • 性能较高,能够将一部分计算的工做放在客户端上,这样服务器只须要处理数据便可。

缺点:

  • 重量级,必须要安装app
  • 软件须要用户去更新,而且要考虑不一样的设备访问。

二、B/S架构

B/S,是 Browser:(浏览器)和 Server(服务器),两个单词的简写,指的是 Web浏览器与服务器端应用程序通信的软件开发架构。

如今全部的网站都是B/S架构,好比知乎、网易云音乐、百度...,用户只需使用浏览器就能访问服务器;

优势:

  • 轻量级,不须要安装客户端,用户不须要主动去更新内容,只须要开发人员更改服务器的内容便可;
  • 多设备同步,全部数据都在网上。

缺点:

  • 性能较低,若是是很酷炫的页面,那么现阶段还实现不了;
  • 移动设备兼容性较好,可是浏览器兼容性较差。

image

1.4 网络基础

一、IP地址

IP地址是网络上每一台设备通信时的身份标识(就像身份证、手机号)。

IP地址长什么样子呢?

192.168.10.10

好比,百度的IP地址就是:

119.75.213.61

特殊的IP地址-表明本机:

127.0.0.1

如何查看当前IP地址?

打开命令行工具,直接输入“ipconfig”
ipconfig 命令

二、域名

域名简单的说,就是给 IP地址起一个容易记忆的名字(就比如人的名字同样)例如百度的域名: www.baidu.com

由于IP地址记忆起来很是不方便,因此平常生活中用户经过域名来访问服务器更加方便。

特殊的域名:localhost(表明本机)。

三、DNS 服务器

什么是 DNSDNS( Domain Name Server),其实就是域名服务器。

输入网址后的访问流程(域名->DNS->IP地址)

查看域名与IP地址的对应关系(ping 命令)

能够用Hosts文件让本身的电脑变成一个属于本身的DNS服务器。

image

四、网络端口(Port)

端口是指计算机与外界进行通信的数据出口(入口),每一个端口为不一样的应用传输不一样数据。

端口号: 每个端口都有一个端口号。范围是从065535

端口号一般跟在IP地址后面,用冒号分隔。例如:192.168.1.1:80www.jd.com:80

经常使用端口号: 80(HTTP)3306(MySQL)21(FTP)

查看本机被占用的端口状况(命令行输入:netstat

image

五、数据库

按照数据结构来组织、存储和管理数据的仓库,软件开发行业通常指的是数据库软件,常见的有 OracleMySQL等。

特色:

  • 数据共享,多用户同时访问数据的稳定性;
  • 故障恢复,数据库软件,提供了一套方法,能够用来发现错误,而且修复错误。
  • 减小数据冗余,因为你们均可以使用同一套数据,没有必要重复建立。

DBA数据库管理员:

从事管理和维护数据库管理系统(DBMS)的相关工做人员的统称。保证数据库的稳定性、安全性、完整性和高性能。

2. Web 服务器

2.1 Web服务器的做用

  • 能够经过浏览器访问或查看Web服务器上的文件资源。
  • 文件资源能够是HTML网页、文本、图片、视频、音频、Web服务器程序等。

2.2 AMP 集成环境

AMPA:ApacheM:MySQLP:PHP

一、Apache:

世界排名第一的服务器软件,特色是:简单速度快,性能稳定。

二、MySQL:

体积小、速度快、使用成本低,并且仍是开源。

三、PHP:

超文本预处理器,直接将代码嵌入到HTML文档中执行,简单易学,容易上手。

2.3 Web服务器软件的安装

在本身的Windows电脑上Web服务器软件 - Wamp

WampServer: Wamp就是 WindowsApacheMysqlPHP集成安装环境,即在 window下的 apache
phpmysql的服务器软件。 PHP扩展、 Apache模块,开启/关闭鼠标点点就搞定,不再用亲自去修改
配置文件了, WAMP它会去作。不再用处处询问 php的安装问题了, WAMP一切都搞定了,这个软件
windows平台上使用的较多。

下载WampWamp官网

安装Wamp:安装的时候要区分版本(64位,32位),点击下一步下一步。

注意:安装目录的路径不能出现中文。

程序安装成功以后,任务栏里面的小图标是绿色的话,说明安装成功。

image

刚刚上面提到过,域名:localhostIP地址:127.0.0.1均可以打开本地服务器:

image

image

当出现wamp页面的时候说明软件安装成功。

2.4 安装的建议与问题

  • 问题1:没法安装软件(请检查安装软件的版本与操做系统匹配)
  • 问题2:安装完成后,web服务器没有正常运行(测试web服务器的端口号是否被占用)
  • 建议1:64位版本、32位版本要分清
  • 建议2:安装目录的路径不要有中文
  • 建议3:提示默认浏览器和默认编辑器的设置可忽略
  • 建议4:安装时建议关闭防火墙
  • 建议5:若是已安装其余的Web服务器软件请先关闭

2.5 Wamp服务器的使用

一、基本功能使用:

修改语言 右击任务栏中的软件小图标==> language ==> chinese

image

Web服务器的启动、中止、运行: 左击小图标 (修改配置文件以后,必定要重启服务器);

image

功能介绍:Apache

image

其中两个配置文件后面可能须要修改,因此这里须要知道在哪找到它们。

看下它的配置文件-httpd.conf,其中 #表示的是注释的意思。

image

功能介绍:MySQL

image

看下它的配置文件-my.ini,其中 ;表示的是注释的意思:

image

功能介绍:PHP Apache是一个web服务器,它自己是不能解析PHP语言的,因此这里也集成了一个PHP解析器

image

看下它的配置文件-php.ini,其中 ;表示的是注释的意思:

image

2.6 Wamp服务器的简单配置

一、为Web服务配置一个域名(仅限本机使用的域名)

找到C:\Windows\System32\drivers\etc\hosts文件并修改

image

将本地的IP设置一个新的域名lxh.com,重启Wamp服务器,在地址栏里输入lxh.com就会跳转到服务器页面:

image

二、自定义Web服务器的根目录

咱们能够看到,当咱们输入本地域名或者 IP的时候,都会弹出来服务器的界面,假如我想要打开一个文件的时候怎么办呢?这时候咱们就须要配置服务器的根目录,只要是在根目录里面的文件,均可以经过服务器打开。

查找并打开安装目录D:\wamp64\bin\apache\apache2.4.23\conf\extra\httpd-vhosts.conf文件:

image

打开修改配置文件,其中ServerName指的是域名,咱们能够将第一步配好的本地域名地址写上去;DocumentRoot D:/lxhAjax<Directory "D:/lxhAjax/">是自定义Web服务器的根目录为D:/lxhAjax文件夹

image

image

三、为Web服务器配置虚拟主机(一台Web服务器当多台用)

在同一局域网下别人能够经过你的 IP访问你的 Web服务器文件夹。
  • httpd-vhosts.conf 文件中查找 Require local
  • Require local 改为 Require all granted

image

不过建议你们不要这样作,安全性不高,电脑里面的东西会被别人看到。

四、注意事项

  • php5.6 如下版本要设置php默认编码,default_charset = UTF-8,不然PHP程序可能没法正确显示中文。
  • httpd.conf文件设置DocumentRoot前,先检查是否已经关闭了虚拟主机,不然可能致使设置无效。
  • 默认状况下Wamp服务器只能被本机访问,若是向被局域网的其余电脑访问须要修改配置

    • httpd-vhosts.conf 文件中查找 Require local
    • Require local 改为 Require all granted
  • 检查网络是否是通的 ping 对方IP
  • 检查防火墙是否开启,若是开启将不能正常被访问
  • 确保端口没有被其它程序占用
  • #”表示注释
  • 配置文件每一行不要增长多于的空格。不然服务器容易报错。
  • 修改配置要格外当心,禁止无心修改其它内容

3. HTTP传输协议

网络协议约定了网络计算机之间数据的传输的方式、数据的格式等。

常见的网络应用底层协议:

  • HTTPHTTPS超文本传输协议
  • FTP文件传输协议
  • SMTP简单邮件传输协议

HTTP协议:

HTTP即超文本传输协议,网站是基于 HTTP协议的,好比咱们在开发网站中常用 cssjs、图片等等都是基于该协议传输的。

组成部分:

HTTP协议是对请求(Request)和响应(Response)的报文内容进行了约束和规范。

请求: 客户机向服务器发送数据

响应: 服务器向客户机发送数据

image

发送并请求请求报文,接收响应报文,这种获取数据的方式咱们称之为HTTP协议。

3.1 请求报文

请求是由客户端发起,其规范格式为:请求行、请求头、请求主体。

image

一、请求行:

由请求方法、请求 URLHTTP协议及版本构成
GET /code/login.php?username=123&password=123 HTTP/1.1
POST /code/login.php HTTP/1.1

二、请求头:

这里设置的主要是一些信息,包含客户端,服务器。
  • User-Agent:浏览器的具体类型,如:User-Agent:Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0
  • Accept:浏览器支持哪些数据类型,如:Accept: text/html,application/xhtml+xml,application/xml;q=0.9;
  • Accept-Charset:浏览器采用的是哪一种编码,如:Accept-Charset: ISO-8859-1
  • Accept-Encoding:浏览器支持解码的数据压缩格式,如:Accept-Encoding: gzip, deflate
  • Accept-Language:浏览器的语言环境,如:Accept-Language zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
  • Host:请求的主机名,容许多个域名同处一个IP地址,即虚拟主机。Host:www.baidu.com
  • Connection:表示是否须要持久链接。Keep-Alive/closeHTTP1.1默认是持久链接,它能够利用持久链接的优势,当页面包含多个元素时(例如Applet,图片),显著地减小下载所须要的时间。要实现这一点,Servlet须要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,而后在正式写出内容以前计算它的大小。如:Connection: Keep-Alive
  • Content-Length:表示请求消息正文的长度。对于POST请求来讲Content-Length必须出现。
  • Content-Type:WEB服务器告诉浏览器本身响应的对象的类型和字符集。例如:Content-Type: text/html; charset='gb2312'
  • Content-EncodingWEB服务器代表本身使用了什么压缩方法(gzip,deflate)压缩响应中的对象。例如:Content-Encoding:gzip
  • Content-LanguageWEB服务器告诉浏览器本身响应的对象的语言。
  • Cookie:最经常使用的请求头,浏览器每次都会将cookie发送到服务器上,容许服务器在客户端存储少许数据。
  • Referer:包含一个URL,用户从该URL表明的页面出发访问当前请求的页面。服务器能知道你是从哪一个页面过来的。Referer: http://www.baidu.com/

三、请求体:

这里是提交给服务器的数据

须要注意的是,若是是往服务器提交数据,须要在请求头中设置Content-Type:application/x-www-form-urlencoded(在ajax中须要手动设置);

3.2 响应报文

响应报文是服务器发回给客户端的。组成部分有状态行,响应头,响应主体。

image

一、状态行:

由协议版本号、状态码和状态信息构成
HTTP/1.1 200 OK

常见的状态码:

  • 1XX:信息状态码

    • 100 Continue 继续,通常在发送post请求时,已发送了http header以后服务端将返回此信息,表示确认,以后发送具体参数信息
  • 2XX:成功状态码

    • 200 OK 正常返回信息
    • 201 Created 请求成功而且服务器建立了新的资源
    • 202 Accepted 服务器已接受请求,但还没有处理
  • 3XX:重定向

    • 301 Moved Permanently 请求的网页已永久移动到新位置。
    • 302 Found 临时性重定向。
    • 303 See Other 临时性重定向,且老是使用 GET 请求新的 URI。
    • 304 Not Modified 自从上次请求后,请求的网页未修改过。
  • 4XX:客户端错误

    • 400 Bad Request 服务器没法理解请求的格式,客户端不该当尝试再次使用相同的内容发起请求。
    • 401 Unauthorized 请求未受权。
    • 403 Forbidden 禁止访问。
    • 404 Not Found 找不到如何与 URI 相匹配的资源。
  • 5XX: 服务器错误

    • 500 Internal Server Error 最多见的服务器端错误。
    • 503 Service Unavailable 服务器端暂时没法处理请求(多是过载或维护)。

二、响应头:

  • Date:响应时间
  • Server:服务器信息
  • Last-Modified:资源最后修改时间 由服务器自动生成
  • ETag:资源修改后生成的惟一标识,由服务器自动生成
  • Content-Length:响应主体长度
  • Content-Type:响应资源的类型

三、响应主体:

即服务端返回给客户端的内容;

4. Ajax 编程

Asynchronous Javascript And XML(异步的 JavascriptXML)。

4.1 Ajax的基本概念

思考:

咱们访问一个普通网站时,当浏览器加载完HTMLCSSJS之后,网站就固定了,若是网站内容发生改变,必须刷新网页后,才能看到更新内容。

Ajax概念:

在浏览器中,咱们可以不刷新页面,经过Ajax的方式去获取一些新的内容。

  • Ajax 不是一门的新的语言,而是对现有技术的综合利用。
  • 本质是在HTTP协议的基础上以异步的方式与服务器进行通讯。
  • 核心是经过浏览器端的js帮咱们预约义的一个异步对象XMLHttpRequest来完成的

AJAX是一种用于建立快速动态网页的技术。经过在后台与服务器进行少许数据交换,AJAX可使网页实现异步更新。这意味着能够在不从新加载整个网页的状况下,对网页的某部分进行更新。

优势:

  • 页面无刷新,用户体验好;
  • 异步通讯,更加快的响应能力;
  • 减小冗余请求,减轻了服务器负担;
  • 基于标准化的并被普遍支持的技术,不须要下载插件或者小程序

缺点:

  • 浏览器对XMLHttpRequest对象的支持度不足,存在兼容性;
  • Ajax干掉了back按钮,即对浏览器后退机制的破坏;
  • 对搜索引擎的支持比较弱;
  • 存在必定的安全问题;
  • 没法用URL直接访问;
  • 开发调试工具的缺少。

Ajax应用场景:

  • 场景1 数据验证
  • 场景2 按需取数据
  • 场景3 自动更新页面

Ajax 包含如下五个部分:

Ajax并不是一种新的技术,而是几种原有技术的结合体。它由下列技术组合而成。
  • 使用CSSXHTML来表示。
  • 使用DOM模型来交互和动态显示。
  • 数据互换和操做技术,使用XMLXSLT
  • 使用XMLHttpRequest来和服务器进行异步通讯。
  • 使用javascript来绑定和调用。

传统Web应用程序与Ajax Web应用程序对比:

image

主要的差异,其实不是JavaScript,不是HTML/XHTMLCSS,而是采用了XMLHttpRequest来向服务器异步的请求XML数据。

同步:

  • 必需要等前面的任务完成,才能继续后面的任务,必定要按顺序执行。

异步:

  • 指某段程序执行时不会阻塞其它程序执行,其表现形式为程序的执行顺序不依赖程序自己的书写顺序。
  • 其优点在于不阻塞程序的执行,从而提高总体执行效率。
  • XMLHttpRequest能够以异步方式的处理程序。

4.2 建立Ajax

Ajax的原理简单来讲,就是经过 XMLHttpRequest对象来向服务器发送异步请求,从服务器得到数据,而后用 javascript来操做 DOM而更新页面。其中最关键的一步就是从服务器得到请求数据。

一、建立XMLHttpRequest对象:

Ajax的核心是 XMLHttpRequest对象,它是 Ajax实现的关键,发送异步请求、接受响应以及执行回调都是经过它来完成。

现代浏览器:

全部现代浏览器( IE7+FirefoxChromeSafari 以及 Opera)均内建 XMLHttpRequest 对象。
var xhr = new XMLHttpRequest();

老版本IE:

老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 对象:
var xhr = new ActiveXObject("Microsoft.XMLHTTP");

为了应对全部的现代浏览器,包括IE5IE6,请检查浏览器是否支持XMLHttpRequest对象。若是支持,则建立 XMLHttpRequest 对象。若是不支持,则建立ActiveXObject

兼容性处理:

var xhr = null;
if(window.XMLHttpRequest){
     //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
    xhr = new XMLHttpRequest();
}else{
    // IE6, IE5 浏览器执行代码
    xhr = new ActiveXObject("Microsoft.XMLHTTP");
}

XMLHttpRequest对象的属性和方法:

image

二、准备请求,设置请求的url等参数:

首先经过 open()方法初始化 XMLHttpRequest对象,接受三个参数:
// 规定请求的类型、URL 以及是否异步处理请求。
xhr.open(method,url,async);

method: 表示的是请求类型的字符串,能够是“GET”或者“POST”。

GET请求:

xhr.open("GET","demo.php",true);

POST请求:

xhr.open("POST","demo.php",true);

url: 第二个参数是要做为请求发送目标的URL

async: 第三个参数是truefalse,表示请求是以异步仍是同步的模式发出。(默认为true,通常不建议为false

  • false:同步模式发出的请求会暂停全部javascript代码的执行,直到服务器得到响应为止,若是浏览器在链接网络时或者在下载文件时出了故障,页面就会一直挂起。
  • true:异步模式发出的请求,请求对象收发数据的同时,浏览器能够继续加载页面,执行其余javascript代码

三、发送请求:

经过 XMLHttpRequest对象的 send()方法,向服务器发送请求。
xhr.send();

GET请求:

通常状况下,使用 Ajax提交的参数多数是些简单的字符串,能够直接使用 GET方法将要提交的参数写到 open方法的 url参数中,此时 send方法的参数为 null或为空。
// get请求是将数据拼接在url后面的
xhr.open("GET",demo.php?name=tsrot&age=24,true);
xhr.send(null);

POST请求:

若是须要像 HTML表单那样 POST数据,请使用 setRequestHeader()来添加 HTTP头。而后在 send()方法中规定你但愿发送的数据:
// post请求须要加一个请求头,而且使用send方法将数据进行发送
xhr.open("POST",demo.php,true);
xhr.setRequestHeder("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
xhr.send(...);

四、处理响应:

当服务器收到浏览器发送的数据后,会响应一个内容,由于不知道何时数据响应回来,因此提供了一个事件方法 onreadystatechange。每当 readyState改变的时候就会触发 onreadystatechange事件, readyState属性:存有 XMLHttpRequest的状态信息。
xhr.onreadystatechange = function(){
    // 为了保证数据完整回来,咱们通常会判断两个值
     if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
    }
}

onreadystatechange:当处理过程发生变化的时候执行里面的函数

readyStateajax处理过程

  • 0:请求未初始化(尚未调用 open())。
  • 1:请求已经创建,可是尚未发送(尚未调用 send())。
  • 2:请求已发送,正在处理中(一般如今能够从响应中获取内容头)。
  • 3:请求在处理中;一般响应中已有部分数据可用了,可是服务器尚未完成响应的生成。
  • 4:响应已完成;您能够获取并使用服务器的响应了。

status状态码属性(详见上面状态码类型):

  • 200:”OK
  • 404: 未找到页面

responseText:得到字符串形式的响应数据;

4.3 Ajax实现一个简单的聊天室

基本html结构:

<h3>简单的Ajax实例聊天室</h3>
<div class="chatbox">
    <!-- 聊天记录界面 -->
    <div class="messages"></div>
    <!-- 输入界面 -->
    <div class="form">
        <div class="input"><textarea></textarea></div>
        <div class="btn">
            <input type="button" class="send" value="发送">
            <input type="button" class="clear" value="清屏">
        </div>
    </div>
</div>

image

js部分:

// 1-发送按钮注册点击事件
var send = document.querySelector(".send");
var clear = document.querySelector(".clear");
var messages = document.querySelector(".messages");
var textarea = document.querySelector(".input").children[0];
send.onclick = function() {
    // 1-获取输入的内容 动态建立一个p标签 添加到 messages中
    var p = document.createElement("p");
    var content = textarea.value;
    if (content != "" && content.trim()) {
        p.innerText = content + ":Levi";
        messages.appendChild(p);
        p.className = "self";
        textarea.value = "";
    }

    // 2-建立Ajax请求
    var xhr;
    if (window.XMLHttpRequest) {
        //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
        xhr = new XMLHttpRequest();
    } else {
        // IE6, IE5 浏览器执行代码
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }

    xhr.open('post', 'chat.php', true);
    // post请求的时候,须要使用setRequestHeader()添加响应头
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
    xhr.send("message=" + content);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var reply = xhr.responseText;
            var p = document.createElement("p");
            p.innerText = "网友:" + reply;
            p.className = "other";
            messages.appendChild(p);
        }
    }

}

// 3-清屏按钮
clear.onclick = function() {
    messages.innerHTML = "";
}

// 4-回车键触发发送按钮
textarea.onkeydown = function(e) {
    e = window.event || e;
    if (e.keyCode == 13) {
        send.onclick();
        e.preventDefault();
    }
}

PHP部分:

<?php 
     header('Content-Type:text/html;charset=utf-8');

        /*建立 对话的队列 */
        $message = array(
            '你好呀!',
            '干吗?',
            '我在睡觉。',
            '上课吧',
            '骗你的',
        );

        /*随机的取了一句话*/
        /*array_rand 去某个数组的随机索引*/
        echo $message[array_rand($message)];

        sleep(1);
?>

PHP部分咱们能够不用深究,只须要知道请求的数据message,在php里其实就是一个随机字符串。

效果图:

image

4.4 复杂的数据格式介绍

HTTP协议中,全部数据最终的传输格式所有都是字符串。若是想要在 HTTP协议中传输一些复杂类型的数据,如数组、对象等,没法直接实现。

后台只有一个,可是开发语言却有不少种,一种后台格式的数据,如何适应所有开发语言的需求呢?因此须要一个统一的数据格式来在各个语言之间传递数据。

4.4.1 XML数据格式

XML( Extensible Markup Language),可扩展标记语言。它也是一个标记语言,因此它里面也是标签,而且也有文档声明。

XML文件的基本格式:

<!-- 1-声明文档 version:版本 encoding:编码 -->
<?xml version = "1.0" encoding="UTF-8"?>

<!-- 2-xml必需要有根节点 root-->
<root>
    <!-- name age相对于对象 -->
    <name>Levi</name>
    <age>18</age>
</root>

注意:

  • 必须有一个根元素
  • 不能够有空格、标签不能够以数字、下划线、或其余特殊符号开头,大小写敏感;
  • 不可交叉嵌套;
  • 特殊符号要使用实体;
  • 注释和HTML同样

虽然能够描述和传输复杂数据,可是其解析过于复杂而且体积较大,因此实际开发已经使用不多了。

Ajax请求XML数据:

首先,新建一个XML数据格式的文件-data.xml

<?xml version = "1.0" encoding="UTF-8"?>

<root>
    <name>Levi</name>
    <age>18</age>
</root>

新建一个PHP文件-xml.php

<?php
    // 设置数据解析格式为xml解析方式
    header("Content-Type:application/xml");
    
    // 将数据返回给前端
    $xml = file_get_contents("data.xml");
    echo $xml;
?>

html里面经过Ajax得到数据:

var xhr = new XMLHttpRequest();
xhr.open("get","xml.php");
xhr.send();
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4 && xhr.status ==200){
        console.log(xhr.responseXML); // 返回XML形式的响应数据
        // DOM里面的api在xml里面一样适用
        console.log(xhr.responseXML.getElementByTagName("name")[0].innerHTML);  // 打印 Levi
    }
}

responseXML:得到XML形式的响应数据。

Ajax中获取到XML数据以后,须要经过xhr.responseXML这个属性来获取数据,获取数据的时候能够直接使用DOM提供的APIresponseText也能够获取到数据,可是获取到的是字符串,没法经过dom`api`来操做。

4.4.2 JSON数据格式

JSON( JavaScript Object Notation),是一种轻量级的数据交换格式,独立语言。

json有别于通常的对象,虽然json也是键值对的存在,可是json的键必需要加双引号,而通常的js对象能够不用加。

json数据的基本格式:

data:[
    { "name":"zs", "age":18, "skill":"吹牛" },
                       ...
    { "name":"ww", "age":28, "skill":"睡觉" }
]

Ajax请求json数据:

前面咱们知道了,前端在拿后台数据的时候,对后台数据处理提供了两个方法,一个是对字符串处理的 responseText方法,还有一个是对 XML格式处理的 responseXML方法,可是惟独没有处理 json数据的方法,因此咱们须要借助于 json内置对象的 JSON.parse方法,将后台的返回的 json字符串,转换成 json对象。
JSON.parse(xhr.responseText);

新建一个PHP文件-json.php

<?php
    // 设置数据解析格式为json格式
    header("Content-Type:application/json");
    
    $person = array('name' =>'Levi' ,'age'=>18,'skill'=>'帅' );
    
    // json_encode 将对象数据转换成json格式的数据返回前端
    echo json_encode($person);
?>

html里面经过Ajax得到数据:

var xhr = new XMLHttpRequest();
    xhr.open("get", "01-json.php");
    xhr.send();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            // 前端拿后台数据的时候,只有两种方式 responseText和responseXML
            // 没有单独为json数据提供一个方法,因此须要将json字符串经过JSON.parse()方法,转换成对象jianrong
            var jsonStr = xhr.responseText;
            var jsonObj = JSON.parse(jsonStr);
            console.log(jsonObj);  // 打印的是一个对象
        }
    }

总结方法:

json字符串,转换成一个对象:JSON.parse(jsonStr);

// 注意,json字符串里面的属性必须是双引号包裹,单引号包裹会报错
var jsonStr = '{"name":"Levi","age":18,"skill":"帅"}';
var obj = JSON.parse(jsonStr);
console.log(obj); // 打印对象 {name: "Levi", age: 18, skill: "帅"}

将对象转换成json格式的字符串:JSON.stringify;

var obj = {
    name: "Levi",
    age: "18",
    skill: "帅"
};
var jsonStr = JSON.stringify(obj);
console.log(jsonStr); //打印{"name":"Levi","age":"18","skill":"帅"}

4.5 Ajax代码的封装

一个页面中,确定不仅是一处须要 ajax请求,因此咱们能够将它封装成一个函数。

Ajax对象获取响应头属性:

xhr.getAllResponseHeaders();   // 获取所有响应头信息 
xhr.getResponseHeader('key');  // 获取指定头信息

代码封装:

// 封装前须要考虑的因素
// 1- 请求的方式
    // get: 须要将数据拼接在url以后
    // post: 须要加一个请求头,而且使用send方法将数据进行发送
// 2- 请求的url地址
// 3- 须要发送的数据
// 4- 添加回调函数success,将请求到的数据返回给调用的函数
    // 判断服务器返回的是什么格式的数据(经过响应头)
        // a- xhr.getAllResponseHeaders();  获取所有响应头信息 
        // b- xhr.getResponseHeader('key'); 获取指定头信息 
function ajax(options) {
    // 默认值处理
    // 设置默认的请求方式为type
    options.type = options.type || "get";
    // 设置默认的请求地址为当前地址栏地址
    options.url = options.url || location.href;
    // 设置默认的请求同步或者异步
    options.async = options.async || "true";
    // 设置请求参数data的默认值
    options.data = options.data || {};
    // 处理用户传进来的请求参数(data)对象
    var dataArr = [];
    for (var k in options.data) {
        dataArr.push(k + "=" + options.data[k]);
    }
    var dataStr = dataArr.join("&");

    // 异步请求对象兼容性处理
    var xhr;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        // IE6及其如下版本   
        xhr = new ActiveXObjcet('Microsoft.XMLHTTP');
    };

    // 判断当前的请求方式,若是是get,将数据拼接在地址后面
    xhr.open(options.type, options.type == "get" ? options.url + "?" + dataStr : options.url, options.async);
    // 当是post请求的时候,须要设置请求头
    if (options.type == "post") {
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    }
    // 发送数据,当是post方式的时候,发送数据
    xhr.send(options.type == "get" ? null : dataStr);
    if (options.async) {
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                // 判断请求的数据是什么类型的
                var type = xhr.getResponseHeader("Content-Type");
                var result;
                if (type.indexOf("json") != -1) {
                    // 若是是json格式的数据,就将其转换成js对象
                    result = JSON.parse(xhr.responseText);
                } else if (type.indexOf("xml") != -1) {
                    // 若是是xml格式的数据,直接返回responseXML
                    result = xhr.responseXML;
                } else {
                    // 若是两种格式都不是,直接返回responseText
                    result = xhr.responseText;
                }
                // 将处理好的数据进行传递
                options.success(result);
            }
        }
    } else {
        // 若是是同步的话就不须要在监测状态改变的状况了
        var type = xhr.getResponseHeader("Content-Type");
        var result;
        if (type.indexOf("json") != -1) {
            result = JSON.parse(xhr.responseText);
        } else if (type.indexOf("xml") != -1) {
            result = xhr.responseXML;
        } else {
            result = xhr.responseText;
        }
        options.success(result);
    }
}

// 调用ajax请求
ajax({
    url: "json.php",
    type: "get",
    data: {name: "levi",age: 18},
    success: function(data) {
        console.log(data);
    }
});
ajax({
    url: "xml.php",
    type: "get",
    data: {name: "levi",age: 18},
    success: function(data) {
        console.log(data);
    }
});

5. jQuery中的Ajax操做

前面的《 jQuery入门详解》中已经讲到了如何经过 jQuery操做 Ajax,这里再为你们总结一遍。

一、$.ajax()方式经常使用参数解析:

方法 做用
url 请求的地址
type 请求的方式
dataType 告诉jQuery,须要按照什么格式对服务器返回的数据进行解析,默认json
data 数据
success 请求成功的回调函数
error 请求失败的回调函数
beforeSend 请求发送以前调用的函数
complete 不论请求是成功仍是失败的,只要请求完成就会调用
timeout 设置请求超时时间

示例代码:

$.ajax({
    // 请求的地址
    url: "04-data.php",
    // 请求的方式
    type: "get",
    // 告诉jQuery,须要按照什么格式对服务器返回的数据进行解析,默认json
    dataType: "json",
    // 数据
    data: {
        msg: "我是来请求数据的"
    },
    // 请求成功的回调函数
    success: function(data) {
        console.log(data);
    },
    // 请求失败的回调函数
    error: function() {
        console.log("失败了");
    },
    // 请求发送以前调用的函数
    beforeSend: function() {
        console.log("请求发送以前调用的函数");
        // 若是返回一个false,那么就会阻止整个请求的发送
        // return false;
        // 用法:能够用做表单验证,当表单内容符合规范的时候发送ajax请求,当不符合的时候就不发送ajax请求
    },
    // 不论请求是成功仍是失败的,只要请求完成就会调用
    complete: function() {
        console.log("请求完成了");
    },
    // 设置请求超时时间(单位:ms),超过这个时间后,就不会请求了
    timeout:2000
});

二、jQuery中的serialize方法:

serialize方法会将表单中全部的内容拼接成 key=value&key=value这样的字符串。

经过这种方式就不要再去手动获取表单中的内容的

<form id="form">
    <input type="text" name="username">
    <input type="text" name="pwd">
    <input type="text" name="phonenumber">
    <input type="text" name="email">

    <button id="btn">获取数据</button>
</form>

<script src="jquery.min.js"></script>
<script>
    $(function() {
        $('#btn').click = function() {
            var dataStr = $('#form').serialize();
            $.ajax({
                url: "json.php",
                //data这个参数能够接收对象,也能够接受 key=value&key=value的这种字符串
                data: dataStr,
                type: "post"
            });
        }
    });
</script>

三、jQuery中的serializeArray方法:

上面的方法咱们能够看到,获取整个数据的时候,是很简单,可是想要进行校验的话就很难,由于上面的方法获取的是一个字符串,不能进行校验,因此此时咱们须要另一个方法, jQuery中的 serializeArray方法。
<form id="form">
    <input type="text" name="username">
    <input type="text" name="pwd">
    <input type="text" name="phonenumber">
    <input type="text" name="email">

    <button id="btn">获取数据</button>
</form>

<script src="jquery.min.js"></script>
<script>
    $(function() {
        $('#btn').click = function() {
            // 获取到的数组拼接成字符串
            var dataArr = $('#form').serializeArray();
            $.ajax({
                url: "json.php",
                data: dataArr,
                type: "post"
            });
        }
    });
</script>

示例代码:ajax模拟表单校验及注册

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>sing in page</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background-color: #F7F7F7;
        }
        
        ul {
            margin: 0;
            padding: 50px;
            list-style: none;
        }
        
        .register {
            width: 800px;
            margin: 50px auto;
            background-color: #FFF;
            border: 1px solid #CCC;
            border-radius: 5px;
        }
        
        li {
            display: flex;
            margin: 20px 0;
        }
        
        label,
        input {
            display: block;
            float: left;
            height: 46px;
            font-size: 24px;
            box-sizing: border-box;
            color: #333;
        }
        
        label {
            width: 200px;
            line-height: 46px;
            margin-right: 30px;
            text-align: right;
        }
        
        input {
            width: 320px;
            padding: 8px;
            line-height: 1;
            outline: none;
            position: relative;
        }
        
        input.code {
            width: 120px;
        }
        
        input.verify {
            width: 190px;
            margin-left: 10px;
        }
        
        input.disabled {
            background-color: #CCC !important;
        }
        
        input[type=button] {
            border: none;
            color: #FFF;
            background-color: #E64145;
            border-radius: 4px;
            cursor: pointer;
        }
        
        .error {
            color: red;
            margin-left: 10px;
            font-size: 12px;
            line-height: 46px;
        }
        
        .tips {
            position: fixed;
            top: 0;
            width: 100%;
            height: 40px;
            text-align: center;
        }
        
        .tips p {
            min-width: 300px;
            max-width: 400px;
            line-height: 40px;
            margin: 0 auto;
            color: #FFF;
            display: none;
            background-color: #C91623;
        }
    </style>
</head>

<body>
    <div class="register">
        <form id="ajaxForm">
            <ul>
                <li>
                    <label for="name">用户名</label>
                    <input type="text" name="name" class="name" id="name">
                    <span class="error"></span>
                </li>
                <li>
                    <label for="pass">请设置密码</label>
                    <input type="password" name="pass" class="pass" id="pass">
                </li>
                <li>
                    <label for="repass">请确认密码</label>
                    <input type="password" name="repass" class="repass" id="repass">
                </li>
                <li>
                    <label for="mobile">验证手机</label>
                    <input type="text" name="mobile" class="mobile" id="mobile">
                </li>
                <li>
                    <label for="code">短信验证码</label>
                    <input type="text" name="code" class="code" id="code">
                    <input type="button" value="获取验证码" class="verify">
                </li>
                <li>
                    <label for="submit"></label>
                    <input type="button" class="submit" value="当即注册" id="submit">
                </li>
            </ul>
        </form>
    </div>
    <div class="tips">
        <p>用户名不能为空</p>
    </div>

    <script src="../05-Form-Validation/js/jquery.min.js"></script>
    <script>
        /*
         * 1.获取短信验证码
         * 1.1 当没有输入手机号的时候  提示请输入手机号
         * 1.2 手机号格式不正确        提示请输入正确的手机号
         * 1.3 调获取短信验证码接口
         * 1.4 显示正在发送中  不能再次发送(防止重复提交)
         * 1.5 当接口成功  按照后台的计时时间  进行倒计时
         * 1.6 当接口失败  提示短信接口繁忙 恢复按钮
         * 1.7 倒计时完成以后  恢复按钮
         * */

        /*
         * 2.注册
         * 2.1 当没有输入用户名的时候  提示请输入用户名
         * 2.2 调注册接口
         * 2.3 显示正在提交 不能再次发送(防止重复提交)
         * 2.4 当接口成功
         *     状态码 10000 成功
         *     状态码 10001 失败 提示用户  用户名已注册  表单后
         *     状态码 10002 失败 没输用户  请输入用户名
         *     恢复按钮
         * 2.5 当接口失败  恢复按钮
         * */
        $(function() {
            /* 警告显示提示 */
            var showTip = function(tip) {
                $(".tips p").html(tip).fadeIn(500).delay(1000).fadeOut(500);
            };

            /* 1.获取短信验证码 */
            $(".verify").on("click", function() {
                /* 当前按钮指定变量 */
                var $btn = $(this);
                /* 判断当前按钮是否有disabled属性,有的话说明已经被点击了,就不让再点击了 */
                if ($btn.hasClass('disabled')) {
                    return false;
                }

                /* 获取手机号 */
                var mobile = $.trim($('#mobile').val());
                /* 判断是否输入内容,没有的话提示信息 */
                if (!mobile) {
                    showTip('请输入手机号');
                    return false;
                }
                /* 判断手机格式 不正确的话提示信息 */
                var regPhone = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/;
                if (!regPhone.test(mobile)) {
                    showTip('请输入正确的手机号');
                    return false;
                }
                /* 调取短信验证码接口 */
                $.ajax({
                    url: 'registerCode.php',
                    type: 'post',
                    dataType: 'json',
                    data: {
                        mobile: mobile
                    },
                    success: function(data) {
                        if (data.code == 10000) {
                            /* 给发送成功的按钮添加一个倒计时 */
                            var time = parseInt(data.result.time);
                            var timer = setInterval(function() {
                                time--;
                                $btn.val(time + '秒后再次获取');
                                /* 倒计时完成以后  恢复按钮*/
                                if (time <= 0) {
                                    $btn.val('获取验证码').removeClass('disabled');
                                    clearInterval(timer);
                                }
                            }, 1000);
                        } else {
                            /* 逻辑上的失败 */
                            $btn.val('获取验证码').removeClass('disabled');
                        }
                    },
                    error: function() {
                        /* 当接口失败,提示短信接口繁忙 */
                        showTip('短信接口繁忙');
                        $btn.val('获取验证码').removeClass('disabled');
                    },
                    beforeSend: function() {
                        /* 点击以后,显示正在发送 */
                        $btn.val('正在发送...').addClass('disabled');
                    }
                });
                $btn.addClass('disabled');
            });
            /* 2.注册功能的实现 */
            $('.submit').on('click', function() {
                /* 当前点击的按钮 */
                var $btn = $(this);
                /* 正在请求当中 不能再次点击 */
                if ($btn.hasClass('disabled')) {
                    return false;
                }
                var username = $("#name").val().trim();
                var password = $("#pass").val().trim();
                var repeatPassword = $("#repass").val().trim();
                var code = $("#code").val().trim();
                var phoneNum = $("#mobile").val().trim();

                /* 调注册接口 */
                $.ajax({
                    type: 'post',
                    url: 'register.php',
                    data: {
                        name: username,
                        pass: password,
                        repass: repeatPassword,
                        code: code,
                        mobile: phoneNum
                    },
                    dataType: 'json',
                    // beforeSend: function() {
                    //     /* 显示正在提交 不能再次发送(防止重复提交)*/
                    //     $btn.val('正在提交...').addClass('disabled');
                    // },
                    success: function(data) {
                        /* 当接口成功 */
                        /* 状态码 10000 成功 */
                        if (data.code == 10000) {
                            /* 提示+跳转登陆页 */
                            showTip('恭喜' + data.result.name + '注册成功,3后秒自动前往登陆页');
                            setTimeout(function() {
                                location.href = 'http://www.baidu.com/';
                            }, 3000);
                        } else if (data.code == 10001) {
                            /* 输入框提示 */
                            $('.error').html('用户名已注册');
                            /* 恢复按钮 */
                            $btn.val('当即注册').removeClass('disabled');
                        } else if (data.code == 10002) {
                            showTip('请输入用户名');
                            /* 恢复按钮 */
                            $btn.val('当即注册').removeClass('disabled');
                        }
                    },
                    error: function() {
                        showTip('系统繁忙!');
                        $btn.val('当即注册').removeClass('disabled');
                    }
                })
            });
        });
    </script>
</body>

</html>

效果图:

image

6. 模板引擎的使用

模板引擎,就是将一段已经写好模板,使用数据进行填充以后生成 html

6.1 模板引擎的使用步骤

一、引入模板引擎插件:

<script src="template-web.js"></script>

二、建立script标签,注意类型是type="text/template",而且要有一个id,模板内部是须要渲染的内容:

<script type="text/template" id="tpl">
    <div>我叫  </div>
    <div>我今年  岁</div>
</script>

三、调用template方法,将数据渲染到模板内:

var obj = {
    name:"Levi",
    age:18
}

// template("模板的id",要将什么数据渲染到模板中)
var html = template("tpl",obj);

四、回到上面的模板部分,在里面添加占位符:

<script type="text/template" id="tpl">
    // {{}} ==> 就是占位符
    // name 和 age 对应的就是对象obj里面的两个属性
    <div>我叫{{name}}</div>
    <div>我今年{{age}}岁</div>
</script>

五、打印调用的字符串:

var html = template("tpl",obj);
console.log(html);  // 打印的就是div字符串

6.2 模板引擎的其余用法

一、$data:

模板一级特殊变量可使用 $data,指的就是获取的数据;
<!-- 能够经过$data拿到 template函数传进来的数据 -->
{{$data["name"]}}

二、条件语句:

{{if value}}...{{/if}}
{{if value1}}...{{else if value2}}...{{/if}}

示例:

<!-- 注意结束必需要有{{/if结尾}} -->
{{if age >= 18}}
    <div>我成年了</div>
{{else}}
    <div>我没有成年了</div>
{{/if}}

三、循环语句:

$index指的是获取当前遍历的索引值; $value指的是获取当前遍历的元素。
{{each target}}
    {{$index}} {{$value}}
{{/each}}

示例:

<script type="text/template" id="tpl">
    {{each idol}}
        <!--$index 获取当前遍历的索引-->
        <!--$value 获取当前正在遍历的元素-->
        <div>第{{$index}}号偶像:{{$value.name}}</div>
    {{/each}}
</script>

<script>
    var obj = {
        name: "Levi",
        age: 18,
        idol:[
            {name : "刘德华"},
            {name : "张学友"},
            {name : "古天乐"}
        ]
    }
    var html = template("tpl", obj);
    // 引入jQuery
    $('body').append(html);
</script>

效果图:

image

注意:这里介绍一个语法as v i,能够手动指定$index$value的量

<script type="text/template" id="tpl">
    {{each idol as v i}}
        <!--i 获取当前遍历的索引-->
        <!--v 获取当前正在遍历的元素-->
        <div>第{{i}}号偶像:{{v.name}}</div>
    {{/each}}
</script>

四、变量:

<!--能够在模板引擎中声明变量-->
{{set temp = data.content}}

示例:

<script type="text/template" id="tpl">
    <!-- 设置一个变量val 用来接收数据的name值 -->
    {{set val = name}}
    <!-- 打印的就是对象的name属性对应的值 -->
    {{val}}  
</script>

<script>
    var obj = {
        name: "Levi",
        age: 18,
        idol:[
            {name : "刘德华"},
            {name : "张学友"},
            {name : "古天乐"}
        ]
    }
    var html = template("tpl", obj);
    // 引入jQuery
    $('body').append(html);
</script>

五、标签“@”的用法:

当一个标签在页面以字符串形式显示的时候,加上“ @”后就会当成标签去解析。

首先根据后台数据,动态建立一个信息表格:

前端渲染:

<button id="btn">获取数据生成表格</button>
<script type="text/template" id="tpl">
    <table width="600" border="1">
        <thead>
            <tr>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>头像</th>
            </tr>
        </thead>
        <tbody>
            <!-- $data 是个一级变量,表示的就是返回的数据 -->
            {{each $data as v i}}
            <tr>
                <td>{{v.name}}</td>
                <td>{{v.age}}</td>
                <td>{{v.gender}}</td>
                <td>{{v.avatar}}</td>
            </tr>
            {{/each}}
        </tbody>
    </table>
</script>

<script src="template-web.js"></script>
<script>
    $(function() {
        // 点击按钮,发送Ajax请求
        $("#btn").click(function() {
            $.ajax({
                url: "tableData.php",
                type: "get",
                success: function(data) {
                    var htmlStr = template("tpl", data);
                    $("body").append(htmlStr);
                }
            });
        });
    });
</script>

后台数据:

<?php 
    header("Content-Type:application/json;charset=utf-8");

    echo '[{"name": "小乔", "age": 18, "gender": "male", "avatar": "<img src=\"1.jpg\" />"}, {"name": "大乔", "age": 18, "gender": "female", "avatar": "<img src=\"1.jpg\" />"}, {"name": "甄姬", "age": 18, "gender": "male", "avatar": "<img src=\"1.jpg\" />"}]';
 ?>

根据上面的代码,咱们能够动态生成一个表格:

image

看到问题所在了,在后台请求回来的图片地址直接以字符串的形式渲染到页面上了。

解决办法:只须要在头像占位那一栏里面加一个@符号

{{each $data as v i}}
<tr>
    <td>{{v.name}}</td>
    <td>{{v.age}}</td>
    <td>{{v.gender}}</td>
    <td>{{@v.avatar}}</td>
</tr>
{{/each}}

再看效果图:

image

此时头像就能够显示了。

6.3 模板引擎原生语法

一、原生语法:

<%= name %>

二、原生语法判断语句:

<%= if(age == 18){ %>
<div>我满18岁了</div>
<% } %>

三、原生语法循环语句:

<% for(var i = 0; i < arr.length; i++){ %>
    <!-- 遍历数据数组arr,将它里面的name属性显现出来 -->
    <div><%= arr[i].name %></div>
<% } %>

6.4 案例:Ajax模拟请求json数据案例

json数据模拟后台数据:

{
    "code": 200,
    "msg": "OK",
    "result": [{
            "tc_id": "193",
            "tc_name": "一代天骄葫芦娃",
            "tc_roster": "攻城狮",
            "tc_gender": "1",
            "tc_cellphone": "",
            "tc_email": "",
            "tc_status": "0",
            "tc_birthday": "1970-01-01",
            "tc_join_date": "2017-06-15"
        },
        {
            "tc_id": "194",
            "tc_name": "用爱感化司马ad",
            "tc_roster": "攻城狮",
            "tc_gender": "0",
            "tc_cellphone": "",
            "tc_email": "",
            "tc_status": "0",
            "tc_birthday": "1970-01-01",
            "tc_join_date": "1970-01-01"
        }
    ]
}

html页面Ajax请求部分:

<!-- 引入jQuery -->
<script src="jquery.min.js"></script>
<!-- 引入模板引擎 -->
<script src="template-web.js"></script>
<!-- 模板引擎渲染数据 -->
<script type="text/template" id="tpl">
    <table>
        <thead>
            <tr>
                <th>序号</th>
                <th>昵称</th>
                <th>性别</th>
                <th>生日</th>
                <th>花名</th>
            </tr>
        </thead>
        <tbody>
            {{each $data.result as v i}}
            <tr>
                <!-- 序号从1开始,因此就是遍历的下标加1 -->
                <td>{{i + 1}}</td>
                <!-- 昵称 -->
                <td>{{v.tc_name}}</td>
                <!-- 后台数据返回的是数字字符串。判断下以男女显示 -->
                <td>{{if v.tc_gender == "1"}}男{{else}}女{{/if}}</td>
                <!-- 生日 -->
                <td>{{v.tc_birthday}}</td>
                <!-- 花名 -->
                <td>{{v.tc_roster}}</td>
            </tr>
            {{/each}}
        </tbody>
    </table>
</script>
<script>
    $(function() {
        $.ajax({
            url: "teacher.json",
            type: "get",
            success: function(data) {
                // 通常后台都会提供接口文档,能够知道数据的名字,也能够直接打印数据在控制台中查看
                console.log(data);
                // 当数据成功返回以后,将数据以表格的形式打印在页面当中
                if (data.code == 200) {
                    var htmlStr = template("tpl", data);
                    $('body').append(htmlStr);
                }
            }
        });
    });
</script>

效果图:

image

6.5 案例:Ajax提供数据实现瀑布流

经过后台提供的图片信息,以及图片连接,动态的生成瀑布流。

首先须要后台提供的接口文档:

接口地址:waterfull.php
请求方式:get
接口参数:page:当前是第几页 pageSize:当前页面须要显示数据的条数
返回类型:json
返回数据:{page: 2,items:[{path:"./images/0011.jpg",text:"文本信息"}...]}  
          page:下一页的页码
          items:返回当前页的数据
                path:图片地址
                text:图片下方的文本

后台程序以及数据(仅攻参考,不是前端的活):

waterfull.php:

<?php
    header('Content-Type:text/html; charset=utf-8');
    
    /*获取数据  字符串*/
    $data = file_get_contents('data.json');

    /*转化php对象? 须要对其操做*/
    $data = json_decode($data);

    /*页码*/
    $page = $_GET['page'];
    /*条数*/
    $pageSize = $_GET['pageSize'];

    /*获取数据的起始索引*/
    $offset = ($page - 1) * $pageSize;

    /*slice 从什么位子开始切割 切割多少条*/
    $result = array_slice($data, $offset, $pageSize);

    /*下一页的页码*/
    $page++;

    /*转化json字符串 输出到前端*/
    echo json_encode(array('page'=>$page, 'items'=>$result));/*{items:[]}*/

    /*延时1秒返回数据*/
    sleep(1);

?>

data.json:

[
    {
        "path": "./images/001.jpg",
        "text": "一支素笔,一杯花茶,一段时光,浅笑又安然一场盛世的繁华,愿不倾城,不倾国,只倾我全部。只为过简单安稳的生活,单纯不平凡。一支素笔,一杯花茶,一段时光,浅笑又安然。早安!"
    },
                    ...
    {
        "path": "./images/100.jpg",
        "text": "青春,青春,一场盛世不平凡。一支素笔,一杯花茶,一段时光,浅笑又安然一场盛世的繁华,愿不倾城,不倾国,只倾我全部。只为过简单安稳的生活,单纯不平凡。一支素笔,一杯花茶,一段时光,浅笑又安然。早安!"
    }
]

Ajax请求后台数据,动态渲染瀑布流:

  • 经过接口文档,以及活动模板将数据渲染到页面;
  • 利用jQuery里面封装的瀑布流插件,实现瀑布流的布局;
  • 经过页面中的“加载更多”按钮,控制显示的数据数量;

Ajax请求数据:

<!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>瀑布流</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: "Microsoft Yahei";
            background: #f5f5f5;
        }
        .box {
            width: 1200px;
            margin: 0 auto;
            padding-top: 40px
        }
        .box > .items {
            position: relative;
        }
        .box > .items > .item {
            width: 220px;
            box-shadow: 2px 2px 2px #999;
            position: absolute;
        }
        .box > .items > .item > p {
            margin: 0;
            padding: 10px;
            background: #fff;
        }
        /*目的是固定高度且不同*/
        .box > .items > .item > img {
            width: 100%;
            display: block;
            height:  px;
        }

        /*目的是固定高度且不同*/
        .box > .items > .item:nth-child(4n) > img {
            width: 100%;
            display: block;
            height: 450px;
        }
        .box > .btn {
            width: 280px;
            height: 40px;
            margin: 30px auto;
            text-align: center;
            line-height: 40px;
            background-color: #CCC;
            border-radius: 6px;
            font-size: 24px;
            cursor: pointer;
        }
        .box > .loading {
            background-color: transparent;
        }
    </style>
</head>

<body>
    <div class="box">
        <div class="items">
            
        </div>
        <div class="btn">加载更多</div>
    </div>

    <script type="text/template" id="tpl">
        {{each items as v i}}
        <div class="item">
            <img src="{{v.path}}" alt="">
            <p>{{v.text}}</p>
        </div>
        {{/each}}
    </script>

    <script src="jquery.min.js"></script>
    <script src="jquery.waterfull.js"></script>
    <script src="template-web.js"></script>

    <script>
    // ajax 请求,一进来先调用一次
    function render(){
        $.ajax({
            url:"waterfull.php",
            type:"get",
            dataType:"json",
            data:{
                // 3-首先去按钮中,找下一页的page属性,若是没有的话,给一个默认值1
                page:$(".btn").data("page") || 1,
                pageSize: 15
            },
            success:function(data){
                var htmlStr = template("tpl",data);
                $(".items").append(htmlStr);
                $(".items").waterfull();
                // 1-将请求回来的数据中表示下一页的页码page存入btn的自定义属性data-page中
                // 2-给按钮加上一个自定义属性page  值就是后台返回的page属性
                //   7-当数据加载完以后,还要将按钮变成正在加载,而且要移除disabled这个类
                $(".btn").data("page",data.page).text("加载更多").removeClass("disabled");
                // 8-数据是有限的,假如请求不到数据以后,须要将按钮置成disabled,而且加上文字“没有更多数据了”
                if(data.items.length == 0){
                    $(".btn").text("没有更多数据了").addClass("disabled");
                }
            }
        });
    }
    render();

    // 4-点击加载更多的时候,调用Ajax请求
    $(".btn").click(function(){
        // 6- 一进来县普安段一下按钮有没有disabled这个类,若是有的话让它不能够被点击
        if($(this).hasClass("disabled")){
            return false;
        }
        render();
        // 5-点击按钮以后改变按钮的状态,和文本
        $(this).text("正在加载中");
        $(this).addClass("disabled");
    });
    </script>
</body>
</html>

其中jquery.waterfull.js为封装的jQuery瀑布流插件:

(function() {
    $.fn.waterFull = function() {
        //1. 肯定一共多少列
        var columns = 5;
        //2. 获取每个元素的宽度
        var width = this.children().width();
        //3. 计算间隔
        var space = (this.width() - width * columns) / (columns - 1);
        //声明数组来保存每一列当前的高度
        var heightArr = [];
        this.children().each(function(index, ele) {
            //4. 为第一行的元素设置定位
            if (index < columns) {
                $(ele).css({
                    top: 0,
                    left: index * (width + space),
                });
                heightArr.push($(ele).height());
            } else {
                //除过第一行以外的全部的内容
                //先计算当前全部列中最短的列
                var minHeight = heightArr[0];
                var minIndex = 0;
                $.each(heightArr, function(index, value) {
                        if (minHeight > value) {
                            minHeight = value;
                            //找到了最短的列所在的索引
                            minIndex = index;
                        }
                    })
                    //将当前要摆放的元素的高度累加到当前列所对应的高度中
                heightArr[minIndex] += $(ele).height() + space;
                //就是最短列的高度加上间隔
                var top = minHeight + space;
                //由于已经找到了要把当前元素放在哪一列
                //因此直接使用列的索引计算便可
                var left = minIndex * (width + space);
                $(ele).css({
                    top: top,
                    left: left,
                })
            }
            //5. 将items的高度设置为最高的那一列的高度
            var maxHeight = heightArr[0];
            $.each(heightArr, function(index, value) {
                maxHeight = maxHeight > value ? maxHeight : value;
            })
            console.log($(this));
            $(this).parent().height(maxHeight)
        });
    }
})()

效果图:

image

除了手动点击按钮以外,咱们还能够监听滚动条的位置,当在底部的时候直接调用加载函数:

$(window).scroll(function(){
    // 获取滚动条当前滚动的距离
    var scrollTop = $(this).scrollTop();
    // 获取整个盒子的高度
    var boxHeight = $(".box").outerHeight();
    // 获取可视区的高度
    var windowHeight = $(window).height();
    // 判断当滚动条的高度大于等于盒子的高度减去可视区的高度的时候,调用加载函数
    if(scrollTop >= boxHeight - windowHeight){
        // 请求数据还须要判断下有没有disabled这个类,没有的时候才能加载
        if(!$(".btn").hasClass("disabled")){
            render();
            $(".btn").text("正在获取数据").addClass("disabled");
        }
    }
});

7. Ajax请求模拟软件

Postman是一款模拟 Ajax请求的软件,根据接口文档,输入请求地址,以及选择请求的方式,再输入须要请求的数据,就能模拟从后台,获取到数据。

image

根据图片的注释,咱们能够大体了解这款软件的用法,根据接口文档填上信息,点击右上角send,就会模拟发送Ajax请求,response返回请求的结果。

8. 同源策略

同源策略最初是在1995年时提出,到目前为止全部浏览器都实行这个政策。

8.1 什么是同源策略

最初它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源",所谓同源就是必需要知足三个条件:
  • 协议相同
  • 域名相同
  • 端口相同

举个例子:

http://www.abc.com/home/index.html这个网址中,协议是http://,域名是www.abc.com,端口是80(默认端口能够省略),下面看几个例子:

URL 说明 是否容许通讯
http://www.a.com/a.html<br/>http://www.a.com/b.html 协议、域名、端口都相同 容许
http://www.a.com/a/a.html<br/>http://www.a.com/b/b.html 协议、域名、端口都相同,不一样文件夹下 容许
http://www.a.com/a.html<br/>http://www.a.com:8000/b.html 协议、域名相同,端口不一样 不容许
http://www.a.com/a.html<br/>https://www.a.com/b.html 域名、端口相同,协议不一样 不容许
http://www.a.com/a.html<br/>https://www.b.com/b.html 协议、端口相同,域名不一样 不容许
http://www.a.com/a.html<br/>http://70.32.92.74/b.html 协议、端口相同,域名和域名对应ip 不容许

8.2 同源策略的目的

同源策略的目的就是为了保护用户信息安全,防止恶意的网站窃取数据。

打个比方,你登陆了某个网站A,同时你又去浏览了另外一个网站B,若是B网站可以读取你A网站里存储的cookie,会发生什么?你在A网站里面的信息,将会被泄露,更可怕的是,cookie每每用来保存用户的登陆状态,若是用户没有退出登陆,B网站就能够冒充用户进行操做。因此“同源策略”是必须得。

8.3 限制范围

随着互联网的发展,“同源策略”愈来愈严格。目前若是非同源,共有三种行为受到限制:
(1) Cookie、LocalStorage 和 IndexDB 没法读取。

(2) DOM 没法得到。

(3) AJAX 请求不能发送。

虽然这些限制是必要的,可是有时很不方便,合理的用途也受到影响。

9. 跨域

同源策略规定, Ajax请求只能发给同源的网址,不然就报错。
  • 因为浏览器的同源策略,使用XHR对象进行跨域请求会直接被浏览器制止
  • html一些标签中的src属性也能够发送请求,至关因而发送了一个get请求
  • src属性中书写的地址,发送出去的请求,是不会受到浏览器同源策略的限制的

下面介绍三种解决跨域的方法

9.1 JSONP

JSONP是服务器与客户端跨源通讯的经常使用方法,最大的特色就是简单适用。老式浏览器所有支持,服务器改造很是小。

实现原理:

jsonp的原理就是:动态的建立一个script标签,将这个script标签的src属性设置为要请求的地址url,将script标签添加到页面以后,src属性会自动向url发送一个get请求,又因为,后台返回的数据格式比较特殊,是一个函数调用的语句,因此咱们提早定义好一个函数,那么这个函数就会在请求成功以后自动被调用,数据也会被传入到这个函数中,最终就相似于ajax请求的回调的效果!

<script>
    // url即请求的地址,赋值给动态建立的script标签的src属性
    function creatScriptTag(url,callback){
        // 一个页面可能会有不少跨域请求,若是回调函数名写死,那么只能用一次
        // 随机生成一个函数名,将回调函数以这个随机生成的名字命名
        var callbackName = "jsonp" + new Data().getTime() + parseInt(Math.random() * 1000);
        // 将回调函数添加到window对象中,相似于添加了一个这个随机函数名的一个全局函数
        window[callbackName] = callback;
        var script = document.createElement('script');
        script.setAttribute('type','text/javascript');
        // 注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。
        script.src = url + "?callback=" + callbackName;
        document.body.appendChild(script);
    }
    creatScriptTag("http://api.ajax.com/data.php", function(data){
        console.log(data);
    })
</script>

jQuery里的JSONP:

jQuery中,发送 Ajax方法的时候,只要定义一个 dataType:"jsonp",便可实现跨域。

9.2 WebSocket

WebSocket是一种通讯协议,正常是由后台操控,使用 ws://(非加密)和 wss://(加密)做为协议前缀。该协议不实行同源政策,只要服务器支持,就能够经过它进行跨源通讯。

下面是一个例子,浏览器发出的WebSocket请求的头信息。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪一个域名。

正是由于有了Origin这个字段,因此WebSocket才没有实行同源政策。由于服务器能够根据这个字段,判断是否许可本次通讯。若是该域名在白名单内,服务器就会作出以下回应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

(本篇完)

上一篇:JavaScript 进阶知识 - 特效篇(二)

相关文章
相关标签/搜索