AJAX
即 Asynchronous [e'sɪŋkrənəs] Javascript And XML, AJAX 不是一门的新的语言,而是对现有技术的综合利用。 本质是在HTTP协议的基础上以异步的方式与服务器进行通信。
1. 同步与异步
同步和异步概念:
同步: 指的就是事情要一件一件做。等做完前一件才能做后一件任务
异步: 不受当前任务的影响,两件事情同时进行,做一件事情时,不影响另一件事情的进行。
编程中:异步程序代码执行时不会阻塞其它程序代码执行,从而提升整体执行效率。
网页异步应用:
-
验证你的用户名是否已经存在(一边输入,一边获取你的信息,和后台比对)。
-
百度搜索提示,及相关内容展示(一边输入,一边找出了你可能要的内容)。
-
新浪微博评论(异步加载)。
XMLHttpRequest可以以异步方式的请求数据处理程序, 可实现对网页的部分更新, 而不是刷新整个页面
2. XMLHttpRequest对象
浏览器内建对象,用于与服务器通信(交换数据) , 由此我们便可实现对网页的部分更新,而不是刷新整个页面。这个请求是异步的,即在往服务器发送请求时,并不会阻碍程序的运行,浏览器会继续渲染后续的结构。
请求由客户端发起,其规范格式为:请求行、请求头、请求主体。
发送get请求
XMLHttpRequest以异步的方式发送HTTP请求,因此在发送请求时,一样需要遵循HTTP协议。
使用XMLHttpRequest发送get请求的步骤 :
//1. 创建一个XMLHttpRequest对象
var xhr = new XMLHttpRequest();
//2. 设置请求行
// 第一个参数:请求方式 get/post
// 第二个参数:请求的地址 需要在url后面拼上参数列表
//是否异步,默认true
xhr.open("get", "01.php?name=Jepson",true);
//3. 设置请求头
//请求头中可以设置Content-Type,用以说明请求主体的内容是如何编码,get请求时没有请求体,无需设置
//4. 设置请求体
//get请求的请求体为空,因为参数列表拼接到url后面了
xhr.send(null);
注意点 :
-
get请求,设置请求行时,需要把参数列表拼接到url后面
-
get请求不用设置请求头, 不用说明请求主体的编码方式
-
get请求的请求体为null
发送post请求
var xhr = new XMLHttpRequest();
// 1. 设置请求行 post请求的参数列表在请求体
xhr.open("post", "02.php");
// 2. 设置请求头, post 请求必须要设置 content-type, 标记请求体内容的解析方式, 不然后端无法解析获取数据
xhr.setRequestHeader( "content-type", "application/x-www-form-urlencoded" );
// 3. 设置请求体
xhr.send( "name=Jepson&age=18" );
注意点 :
-
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的状态发生状态发生改变时,会触发这个事件。
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
//1. 获取状态行
console.log("状态行:"+xhr.status);
//2. 获取响应头
console.log("所有的响应头:"+xhr.getAllResponseHeaders());
console.log("指定响应头:"+xhr.getResponseHeader("content-type"));
//3. 获取响应体
console.log(xhr.responseText);
}
}
【聊天机器人案例】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #F7F7F7;
}
h3 {
text-align: center;
}
.chatbox {
width: 500px;
height: 500px;
margin: 0 auto;
border: 1px solid #CCC;
background-color: #FFF;
border-radius: 5px;
}
.messages {
height: 350px;
padding: 20px 40px;
box-sizing: border-box;
border-bottom: 1px solid #CCC;
overflow: scroll;
}
.messages h5 {
font-size: 20px;
margin: 10px 0;
}
.messages p {
font-size: 18px;
margin: 0;
}
.self {
text-align: left;
}
.other {
text-align: right;
}
.form {
height: 150px;
}
.form .input {
height: 110px;
padding: 10px;
box-sizing: border-box;
}
.form .btn {
height: 40px;
box-sizing: border-box;
border-top: 1px solid #CCC;
}
.form textarea {
display: block;
width: 100%;
height: 100%;
box-sizing: border-box;
border: none;
resize: none;
outline: none;
font-size: 20px;
}
.form input {
display: block;
width: 100px;
height: 30px;
margin-top: 5px;
margin-right: 20px;
float: right;
}
</style>
</head>
<body>
<h3>简单的Ajax实例</h3>
<div class="chatbox">
<!-- 聊天内容 -->
<div class="messages">
<div class="self">
<h5>我说</h5>
<p>你好</p>
</div>
<div class="other">
<h5>对方说</h5>
<p>你好</p>
</div>
</div>
<div class="form">
<div class="input">
<textarea></textarea>
</div>
<div class="btn">
<input type="button" value="发送" id='btn'>
</div>
</div>
</div>
<script>
// 聊天机器人思路:
// 1. 给发送按钮, 添加点击事件
// 2. 获取 textarea 里面内容, 动态创建 "我说" 结构, div 类名 self, 追加到 messages 中
// 3. 发送请求到后台, 后台返回一个随机的文本
// 4. 前端处理响应, 动态创建 "他说" 结构, div 类名 other, 追加到 messages 中
var btn = document.getElementById("btn");
// document.querySelector( "选择器" ); 返回一个 dom 对象
// html5 中新增的获取元素方法
var textarea = document.querySelector(".input > textarea"); // 获取到 textarea
var messages = document.querySelector(".messages"); // 获取到 messages
btn.onclick = function() {
// 获取 textarea 的内容, 表单元素, 通过 value 来获取内容
var content = textarea.value;
// 动态创建我说结构, div 类名 self, 追加到 messages 中
var div = document.createElement( "div" );
div.className = "self";
div.innerHTML = "<h5>我说</h5><p>" + content + "</p>";
messages.appendChild( div );
// 让 dom 元素滚动到可视区域内
div.scrollIntoView();
// 清空 textarea 内容
textarea.value = "";
// 1. 发送 get 请求, 将 content 传递过去 (可不传)
var xhr = new XMLHttpRequest();
xhr.open( "get", "09-talking.php?content=" + content );
xhr.send( null );
// 2. 监听处理响应
xhr.onreadystatechange = function() {
if ( xhr.readyState === 4 ) {
if ( xhr.status === 200 ) {
// 响应成功
// xhr.responseText 获取响应文本
var result = xhr.responseText;
// 动态创建他说结构, div 类名 other, 追加到 messages 中
var div = document.createElement("div");
div.className = "other";
div.innerHTML = "<h5>对方说</h5><p>" + result + "</p>";
messages.appendChild( div );
// 让 dom 元素滚动到可视区域内
div.scrollIntoView();
}
}
}
}
</script>
</body>
</html>
//talking.php
<?php
header("content-type:text/html;charset=utf-8");
$results = array(
"吃药了没?",
"不约。。",
"爱过",
"你今天长的真帅!",
"这你也信",
"曾经有一份真挚的爱情摆在我面前,我却没有珍惜",
"情不知所以,一往而深",
"陪伴是最长情的告白",
"死鬼, 一般去~",
"流氓!"
);
// array_rand: 随机获取数组的一个下标
$random = array_rand( $results, 1 );
// sleep 模拟网络延迟
sleep(1);
echo $results[$random];
?>
3. 数据交互
浏览器端只是负责用户的交互和数据的收集以及展示,真正的数据都是存储在服务器端的。
我们现在通过ajax的确可以返回一些简单的数据(一个字符串),
但是在实际开发过程中,肯定会会设计到大量的复杂类型的数据传输,
比如数组、对象等,但是每个编程语言的语法都不一样。
因此我们会采用通过的数据交换格式(XML、JSON)来进行数据的交互。
XML(了解即可)
什么是XML
-
XML 指可扩展标记语言(EXtensible Markup Language)
-
XML 是一种标记语言,很类似 HTML
-
XML 的设计宗旨是传输数据,而非显示数据
-
XML 标签没有被预定义。您需要自行定义标签。
语法规范
-
第一行必须是版本信息
-
必须有一个根元素(有且仅有一个)
-
标签不可有空格、不可以数字或.开头、大小写敏感
-
不可交叉嵌套,都是双标签,如果是单标签,必须闭合
-
属性双引号(浏览器自动修正成双引号了)
-
特殊符号要使用实体
-
注释和HTML一样
<?xml version="1.0" encoding="utf-8" ?>
<students>
<student>
<name>张三</name>
<age>18</age>
<gender>男</gender>
<desc>路人甲</desc>
</student>
<student>
<name>李四</name>
<age>20</age>
<gender>男</gender>
<desc>路人乙</desc>
</student>
</students>
php获取xml文件的内容
// 注意: 如果需要返回 xml 数据, 需要将 content-type 改成 text/xml, 不然浏览器以 text/html 解析
header( 'content-type:text/xml;charset=utf-8' );
// file_get_content 用于获取文件的内容
// 参数: 文件的路径
$result = file_get_content( "data.xml" );
echo $result;
js解析xml
//获取服务端返回的xml数据,需要使用xhr.responseXML,这是一个document对象,可以使用DOM中的方法查找元素。
var data = xhr.responseXML;
//获取所有的学生
var students = data.querySelectorAll("student");
缺点:虽然可以描述和传输复杂数据,但是其解析过于复杂, 并且体积较大,所以实现开发已经很少使用了。
JSON数据
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript 规范,采用独立于编程语言的文本格式来存储和表示数据。
-
数据在 键值对 中
-
数据由逗号分隔(最后一个 键值对 不能带逗号)
-
花括号保存对象,方括号保存数组
-
键使用双引号
var obj = {a: 'Hello', b: 'World'}; //这是一个对象
// 这是一个 JSON 字符串,本质是一个字符串
var json = '{"a": "Hello", "b": "World"}';
JSON数据在不同语言进行传输时,类型为字符串,不同的语言各自也都对应有解析方法,解析完成后就能很方便的使用了
// 1. js 对象或数组 => json字符串 JSON.stringify( obj/arr );
// 2. json 字符串 => js 对象或者数组 JSON.parse( json字符串 );
php处理json
- php关联数组 ==> json ( json_encode )
// php的关联数组
$obj = array(
"a" => "hello",
"b" => "world",
"name" => "鹏鹏"
);
//json字符串
$json = json_encode( $obj );
echo $json;
- json ==> php对象/关联数组 ( json_decode )
$json = '{"a": "Hello", "b": "World"}';//json字符串
//第一个参数:json字符串
//第二个参数:
//false,将json转换成对象(默认)
//true:将json转换成数组(推荐)
$obj = json_decode($json,true);
echo $obj['a'];
//通过json文件获取到的内容就是一个json字符串。
$data = file_get_contents("data.json");
//将json转换成数组
$result = json_decode($data, true);
print_r($result);
JS处理json
-
JS对象 ==> JSON字符串 JSON.stringify(obj)
//obj是一个js对象
var obj = {a: 'Hello', b: 'World'}
//result就变成了一个json字符串了
var result = JSON.stringify(obj);// '{"a": "Hello", "b": "World"}'
JSON字符串 ==> JS对象 JSON.parse(obj)
//json是一个json字符串
var json = '{"a": "Hello", "b": "World"}';
//obj就变成了一个js对象
var obj = JSON.parse(json);// {a: 'Hello', b: 'World'}
使用json进行数据传输
思考:
-
js有一个对象,如何发送到php后台
-
php中有一个对象,如何发送到前台。
4. 兼容性处理 (了解, 不用处理)
现在一般最多兼容到 IE8, 这里以后见到了知道是在处理兼容性就行了
var xhr = null;
if(XMLHttpRequest){
//现代浏览器 IE7+
xhr = new XMLHttpRequest();
}else{
//老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 对象:
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
5. 封装ajax工具函数
每次发送ajax请求,其实步骤都是一样的,重复了大量代码,我们完全可以封装成一个工具函数。
//1. 创建xhr对象
//2. 设置请求行
//3. 设置请求头
//3. 设置请求体
//4. 监听响应状态
//5. 获取响应内容
参数提取
参数名 | 参数类型 | 描述 | 传值 | 默认值 |
---|---|---|---|---|
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必须传递,否则直接不发送请求
if(!obj || typeof obj !== "object"){
return;
}
// 如果type传递的是post,那就发送post请求,否则发送get请求
var type = obj.type == "post"?"post":'get';
var url = obj.url;
if(!url){
return;
}
// 只有当async传递了false,才会发送同步请求,不然只发送异步请求
var async = obj.async == false? false:true;
// 传递的参数
var data = options.data;
// 需要一个方法, 将 data 对象转换成 params 字符串
// parse 方法, 将 对象 转成 username=pp&password=123456 的格式
var params = parse( data );
完整版本
var $ = {
ajax: function (options) {
//如果options参数没有传递,直接返回。
if (!options || typeof options !== "object") {
return;
}
//处理默认参数
//如果参数不是post,那就默认为get
var type = options.type == "post" ? "post" : "get";
//如果没有传url,那就传当前地址
var url = options.url || location.pathname;
//如果参数不是false,那就默认是true,发异步请求
var async = options.async == false ? false : true;
var params = this.getParams(options.data);
var xhr = new XMLHttpRequest();
//设置请求行
if (type == "get") {
url = url + "?" + params;
}
xhr.open(type, url, async);
//设置请求头
if (type == "post") {
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
}
//设置请求参数
xhr.send(params);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
/*根据响应头的content-type属性指定方法接收到的内容*/
var contentType = xhr.getResponseHeader('content-type');
var data = null;
if (contentType.indexOf('json') > -1) {
data = JSON.parse(xhr.responseText);
} else if (contentType.indexOf('xml') > -1) {
data = xhr.responseXML;
} else {
data = xhr.responseText;
}
/*执行成功函数*/
options.success && options.success(data);
} else {
options.error && options.error(xhr.responseText);
}
}
}
},
getParams: function (obj) {
//将obj对象转换成参数
//将对象转换成参数列表
if (!obj) {
return null;
}
var arr = [];
for (var k in obj) {
arr.push(k + "=" + obj[k]);
}
return arr.join("&");
}
}
$.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>Document</title>
</head>
<body>
<input type="text" id="inp">
<button id="btn">发送 get 请求</button>
<script src="./jquery-1.12.4.js"></script>
<script>
// 点击按钮, 发送 get 请求
$('#btn').click(function() {
// 发送 ajax 请求
$.ajax({
type: "get",
url: "06-get.php",
data: {
username: "pp",
password: "123456"
},
// timeout 可以设置超时时间, 表示如果 2s 内, 响应还没有回来, 就认为超时
timeout: 2000,
// 发送ajax前,会调用的函数,
// 如果这个函数返回 false,(注意: 必须返回false) 这次请求就不发送了
// 一般 beforeSend 中用于表单校验
beforeSend: function() {
if ( $('#inp').val() === "" ) {
alert("请输入内容");
return false;
}
console.log( "已输入内容, 进行请求" );
},
// 成功的回调函数
success: function( info ) {
console.log( info )
},
// 失败的回调函数
error: function() {
alert( "服务器繁忙" );
},
// 不管成功还是失败都会调用的函数
complete: function() {
console.log( "不管成功还是失败都会调用的 complete" );
}
});
});
</script>
</body>
</html>
6. 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({
type:"get",//请求类型
url:"02.php",//请求地址
data:{name:"zs", age:18},//请求数据
dataType:"json",//希望接受的数据类型
timeout:5000,//设置超时时间
beforeSend:function () {
//alert("发送前调用");
},
success:function (data) {
//alert("成功时调用");
console.log(data);
},
error:function (error) {
//alert("失败时调用");
console.log(error);
},
complete:function () {
//alert("请求完成时调用");
}
});
其他api(了解)
//$.post(url, callback, [dataType]);只发送post请求
//$.get(url, callback, [dataType]);
//$.getJSON(url, callback);
//$.getScript(url,callback);//载入服务器端的js文件
//$("div").load(url);//载入一个服务器端的html页面。