XMLHttpRequest的基本使用
- 什么XMLHttpRequest
XMLHttpRequest(简称 xhr)是浏览器提供的 Javascript 对象,通过它,可以请求服务器上的数据资源。之前所学的 jQuery 中的 Ajax 函数,就是基于 xhr 对象封装出来的。
原生Ajax使用
get请求基本使用
- 步骤:
- 创建xhr对象
- 调用open:设置请求方式和请求地址
- 调用send: 发送请求(这一步是异步操作)
- 设置onreadystatechange事件,监听请求的各种状态
- readyState是xhr的属性,用来表示请求发送的状态
- 取值为4代表下载完毕
- 必须确保readyState为4才能使用响应的数据
- xhr.status 代表请求是否成功
- 200代表请求是成功的
- xhr.responseText 代表接收的响应内容
- readyState是xhr的属性,用来表示请求发送的状态
// 1 创建xhr对象
var xhr = new XMLHttpRequest();
// 2 调用open:设置请求方式和请求地址
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks');
// 3 调用send: 发送请求,这一步是异步操作
xhr.send();
// 4 设置事件,监听请求的各种状态
// - readyState是xhr的属性,用来表示请求发送的状态
// - 取值为4代表下载完毕
// - 必须确保readyState为4才能使用响应的数据
// - 进一步检测:
// - xhr.status 代表请求是否成功
// - 200代表请求是成功的
xhr.onreadystatechange = function () {
// 4.1 检测xhr.readyState取值和xhr.status取值
if (xhr.readyState === 4 && xhr.status === 200) {
// 4.2 接收响应的数据即可
// - 原生接收的响应内容是JSON格式,需要自己进行转换
// - jQuery会自动转换
console.log(xhr.responseText);
}
};
了解xhr对象的readyState属性
XMLHttpRequest 对象的 readyState 属性,用来表示当前 Ajax 请求所处的状态。每个 Ajax 请求必然处于以下状态中的一个:
- 使用xhr发起带参数的GET请求
<script>
// 1 创建xhr对象
var xhr = new XMLHttpRequest();
// 2 调用open:设置请求方式和请求地址
// - 如果希望设置get请求的请求参数,需要放置在open()参数2地址的最后位置
// - 书写方式为: 地址?名=值&名=值....
// - 名称说明: 名=值&名=值称为url编码格式 urlencoded
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks?id=3&name=jack&age=18&gender=男');
// 3 调用send: 发送请求,这一步是异步操作
xhr.send();
// 4 设置事件,监听请求的各种状态
xhr.onreadystatechange = function () {
// 4.1 检测xhr.readyState取值和xhr.status取值
if (xhr.readyState === 4 && xhr.status === 200) {
// 4.2 接收响应的数据即可
console.log(xhr.responseText);
}
};
</script>
查询字符串
-
什么是查询字符串
- 定义:查询字符串(URL 参数)是指在 URL 的末尾加上用于向服务器发送信息的字符串(变量)。
- 格式:将英文的 ? 放在URL 的末尾,然后再加上 参数=值 ,想加上多个参数的话,使用 & 符号进行分隔。以这个形式,可以将想要发送给服务器的数据添加到 URL 中。
// 不带参数的 URL 地址
http://www.HANGTIAN.top:3006/api/getbooks
// 带一个参数的 URL 地址
http://www.HANGTIAN.top:3006/api/getbooks?id=1
// 带两个参数的 URL 地址
http://www.HANGTIAN.top:3006/api/getbooks?id=1&bookname=西游记
GET请求携带参数的本质
无论使用 .get(),又或者直接使用 xhr 对象发起 GET 请求,当需要携带参数的时候,本质上,都是直接将参数以查询字符串的形式,追加到 URL 地址的后面,发送到服务器的。
$.get('url', {name: 'zs', age: 20}, function() {})
// 等价于
$.get('url?name=zs&age=20', function() {})
$.ajax({ method: 'GET', url: 'url', data: {name: 'zs', age: 20}, success: function() {} })
// 等价于
$.ajax({ method: 'GET', url: 'url?name=zs&age=20', success: function() {} })
URL编码与解码
- 什么是URL编码
URL 地址中,只允许出现英文相关的字母、标点符号、数字,因此,在 URL 地址中不允许出现中文字符。 如果 URL 中需要包含中文这样的字符,则必须对中文字符进行编码(转义)。 URL编码的原则:使用安全的字符(没有特殊用途或者特殊意义的可打印字符)去表示那些不安全的字符。 URL编码原则的通俗理解:使用英文字符去表示非英文字符。
http://www.HANGTIAN.top:3006/api/getbooks?id=1&bookname=西游记
// 经过 URL 编码之后,URL地址变成了如下格式:
http://www.HANGTIAN.top:3006/api/getbooks?id=1&bookname=%E8%A5%BF%E6%B8%B8%E8%AE%B0
- 如何对URL进行编码与解码
- 浏览器提供了 URL 编码与解码的 API,分别是:
- encodeURI() 编码的函数
- decodeURI() 解码的函数
encodeURI('黑马程序员') // 输出字符串 %E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98 decodeURI('%E9%BB%91%E9%A9%AC') // 输出字符串 黑马
- 浏览器提供了 URL 编码与解码的 API,分别是:
- URL编码的注意事项
由于浏览器会自动对 URL 地址进行编码操作,因此,大多数情况下,程序员不需要关心 URL 地址的编码与解码操作。
- 更多关于 URL 编码的知识,请参考如下博客: (blog.csdn.net/Lxd_0111/ar…)
使用xhr发起POST请求
- 步骤:
① 创建 xhr 对象
② 调用 xhr.open() 函数
(固定写法)
④ 调用 xhr.send() 函数,
⑤ 监听 xhr.onreadystatechange 事件
- 使用xhr发起POST请求
<script>
// 1 创建xhr对象
var xhr = new XMLHttpRequest();
// 2 调用open
xhr.open('POST', 'http://www.liulongbin.top:3006/api/addbook');
// 3 设置Content-Type内容格式(固定写法)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 4 调用send()
// - 如果具有请求参数,书写在send中,格式也是url编码格式(名=值&名=值...)
xhr.send('bookname=老人与海&author=海明威&publisher=大海图书出版社');
// 5 设置readystatechange事件,接收响应的数据
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
</script>
get与post发送方式的区别
- 请求参数的书写位置不同:
- get请求方式:在xhr.open()的url后面使用?连接
- post请求:在xhr.send()中书写
- post请求需要设置Content-Type
数据交换格式
- 什么是数据交换格式
数据交换格式,就是服务器端与客户端之间进行数据传输与交换的格式。 前端领域,经常提及的两种数据交换格式分别是 XML 和 JSON。其中 XML 用的非常少,所以,我们重点要学习的数据交换格式就是 JSON。
JSON
-
什么是JSON
- 概念:JSON 的英文全称是 JavaScript Object Notation,即“JavaScript 对象表示法”。简单来讲,JSON 就是 Javascript 对象和数组的字符串表示法,它使用文本表示一个 JS 对象或数组的信息,因此,JSON 的本质是字符串。
- 作用:JSON 是一种轻量级的文本数据交换格式,在作用上类似于 XML,专门用于存储和传输数据,但是 JSON 比 XML 更小、更快、更易解析。
- 现状:JSON 是在 2001 年开始被推广和使用的数据格式,到现今为止,JSON 已经成为了主流的数据交换格式。
-
JSON的两种结构
JSON 就是用字符串来表示 Javascript 的对象和数组。所以,JSON 中包含和两种结构,通过这两种结构的相互嵌套,可以表示各种复杂的数据结构。
- 对象结构
:对象结构在 JSON 中表示为 { } 括起来的内容。数据结构为 { key: value, key: value, … } 的键值对结构。其中,key 必须是使用的字符串,value 的数据类型可以是 6种类型。
{
name: "zs",
'age': 20,
"gender": '男',
"address": undefined,
"hobby": ["吃饭", "睡觉", '打豆豆']
say: function() {}
}
{
"name": "zs",
"age": 20,
"gender": "男",
"address": null,
"hobby": ["吃饭", "睡觉", "打豆豆"]
}
- 数组结构
:数组结构在 JSON 中表示为 [ ] 括起来的内容。数据结构为 [ "java", "javascript", 30, true … ] 。数组中数据的类型可以是 6种类型。
[ "java", "python", "php" ]
[ 100, 200, 300.5 ]
[ true, false, null ]
[ { "name": "zs", "age": 20}, { "name": "ls", "age": 30} ]
[ [ "苹果", "榴莲", "椰子" ], [ 4, 50, 5 ] ]
-
JSON语法注意事项
① 属性名必须使用双引号包裹
② 字符串类型的值必须使用双引号包裹
③ JSON 中不允许使用单引号表示字符串
④ JSON 中不能写注释
⑤ JSON 的最外层必须是对象或数组格式
⑥ 不能使用 undefined 或函数作为 JSON 的值
:在计算机与网络之间存储和传输数据。
:用字符串来表示 Javascript 对象数据或数组数据
JSON和JS对象的关系
JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。例如:
//这是一个对象
var obj = {a: 'Hello', b: 'World'}
//这是一个 JSON 字符串,本质是一个字符串
var json = '{"a": "Hello", "b": "World"}'
JSON和JS对象的互转
- 要实现从 JSON 字符串转换为 JS 对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}')
//结果是 {a: 'Hello', b: 'World'}
- 要实现从 JS 对象转换为 JSON 字符串,使用 JSON.stringify() 方法
var json = JSON.stringify({a: 'Hello', b: 'World'})
//结果是 '{"a": "Hello", "b": "World"}'
序列化和反序列化
- 把\color{blue}{数据对象}$$\color{red}{转换为}$$\color{blue}{字符串}的过程,叫做,例如:调用 JSON.() 函数的操作,叫做 JSON 序列化。
- 把\color{blue}{字符串}$$\color{red}{转换为}$$\color{blue}{数据对象}的过程,叫做,例如:调用 JSON.() 函数的操作,叫做 JSON 反序列化。
封装ajax函数
<script>
// 封装用来发送ajax请求的函数
// 参数:
// 对象
// - type 请求方式
// - url 请求地址
// - data 请求参数
// - success 回调函数
function ajax(options) {
// 1 创建xhr对象
var xhr = new XMLHttpRequest();
// 2 设置请求的相关信息: 需要根据请求方式分别设置
// - 统一保存数据
var data = urlencoded(options.data);
// 2.1 将请求方式统一转换为大写(或小写)
var type = options.type.toUpperCase();
// 2.2 对请求方式进行检测
if (type === 'GET') {
xhr.open('GET', options.url + '?' + data);
xhr.send();
} else if (type === 'POST') {
xhr.open('POST', options.url);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(data);
}
// 3 设置事件接收响应内容
xhr.onreadystatechange = function () {
// 3.1 检测
if (xhr.readyState === 4 && xhr.status === 200) {
// 3.2 将JSON格式的字符串转换为对象
var res = JSON.parse(xhr.responseText);
options.success(res);
}
};
}
</script>
ajax level2新功能: 超时时间设置
-
设置方式:
- 属性: xhr.timeout = 超时时间; // 毫秒单位
- 时间: xhr.ontimeout = function() { 请求超时后,触发的事件 };
<script> var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks'); // 设置请求的超时时间(毫秒单位) xhr.timeout = 500; // 设置事件,对超时进行处理 xhr.ontimeout = function () { console.log('网络开小差了,请稍后再试!~'); }; xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); } }; </script>
FormData的使用
- 作用:
- 可以快速处理表单的数据
- 可以进行文件上传
- 注意点:
- 发送FormData需要使用POST请求方式
- 不需要单独设置Content-Type
<body>
<!-- 设置form标签,用来进行formdata操作 -->
<form id="testForm">
<!-- 如果要表单元素数据被请求发送,必须设置name -->
<input type="text" name="username">
<input type="password" name="password">
<!-- 设置按钮,点击后,使用FormData处理表单数据 -->
<button type="button" id="btn">ajax提交</button>
</form>
<script>
// 1 空FormData对象,添加数据后发送
// 1.1 创建FormData对象
var fd = new FormData(); // 空的FormData对象
// 1.2 向fd中添加一些数据
fd.append('name', 'jack');
fd.append('age', 18);
// 1.3 使用POST方法将fd发送到对应接口(此处的接口为formdata)
// - 无需设置之前post的content-type
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata');
xhr.send(fd); // 将fd放入在send()参数中即可
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
// 2 通过FormData对象管理表单元素,再发送(同时也可以添加数据)
document.getElementById('btn').onclick = function () {
// 2.1 创建FormData对象,传入DOM对象形式的form标签到参数中
var testForm = document.getElementById('testForm');
var fd = new FormData(testForm); // 空的FormData对象
// 2.1.1 也可以在存在form的基础上,自己添加数据
fd.append('name', 'rose');
fd.append('age', 21);
// 2.3 使用POST方法将fd发送到对应接口(此处的接口为formdata)
// - 无需设置之前post的content-type
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata');
xhr.send(fd); // 将fd放入在send()参数中即可
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
}
</script>
</body>
使用FormData上传文件
<body>
<input type="file" id="iptFile">
<button type="button" id="btn">点击上传文件</button>
<img src="" alt="" id="pic">
<script>
/*
步骤:
1 准备结构(文件域)
2 检测用户是否选择了文件
3 使用FormData保存文件信息
4 通过ajax发送
5 响应处理,展示服务端获取到的图片
*/
// 1 给按钮设置点击事件
var btn = document.getElementById('btn');
var iptFile = document.querySelector('#iptFile');
var pic = document.getElementById('pic');
btn.onclick = function () {
// 2 检测是否上传了文件,需要检测文件域的files属性
// - files是一个伪数组,可以通过判断length,检测是否选择了文件
console.dir(iptFile);
if (iptFile.files.length === 0) {
// 说明没有选择文件
alert('请选择文件后提交!~');
return;
}
// 3 通过FormData保存文件信息
var fd = new FormData();
// - avatar是接口中规定的请求参数名称
// - files[0]代表选择的文件的相关信息
fd.append('avatar', iptFile.files[0]);
// 4 发送post形式的ajax,将fd发送给服务端处理
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar');
xhr.send(fd);
// 5 接收响应数据
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var res = JSON.parse(xhr.responseText);
// 5.1 检测上传是否成功
if (res.status === 200) {
// 5.2 将响应的图片在线地址,放入到img中展示
pic.src = 'http://www.liulongbin.top:3006' + res.url
}
}
}
};
</script>
</body>
上传进度条功能
- xhr.upload.onprogress 上传中实时触发事件
- 事件对象e的属性
- e.lengthComputable 文件长度使用可用
- e.loaded 以上传大小
- e.total 总大小
- 事件对象e的属性
- xhr.upload.onload 上传完毕时触发事件
<!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>
<link rel="stylesheet" href="./lib/bootstrap.css">
<script src="./lib/jquery.js"></script>
</head>
<body>
<input type="file" id="iptFile">
<button type="button" id="btn">提交</button>
<!-- 设置进度条需要的结构 -->
<!-- 这个div是进度条外面的盒子 -->
<div class="progress" style="width:500px;margin:10px 0;">
<!-- 这个div是会变长的内部的盒子 -->
<div class="progress-bar progress-bar-info progress-bar-striped active" id="percent" style="width:0%">0%</div>
</div>
<script>
/*
1 检测上传过程的事件
xhr.upload.onprogress = function(e) ...
2 检测文件大小是否可用
e.lengthComputable 布尔值
3 计算进度
e.loaded 已加载的大小
e.total 总大小
3.1 计算方式
e.loaded / e.total 上传的进度
制作进度条功能的思路:
- 设置内外两个盒子,外部盒子定宽度,内部盒子宽度默认为0
- 上传中,根据上传的进度设置内部盒子宽度对应改变即可
xhr.upload.onload 上传完毕后触发的事件
*/
var btn = document.getElementById('btn');
var iptFile = document.querySelector('#iptFile');
var pic = document.getElementById('pic');
btn.onclick = function () {
// 2 检测是否上传了文件,需要检测文件域的files属性
if (iptFile.files.length === 0) {
alert('请选择文件后提交!~');
return;
}
// 3 通过FormData保存文件信息
var fd = new FormData();
fd.append('avatar', iptFile.files[0]);
// 4 发送post形式的ajax,将fd发送给服务端处理
var xhr = new XMLHttpRequest();
// 设置上传文件的进度监测
xhr.upload.onprogress = function (e) {
// 判断e.lengthComputable是否为true,为true表示可以进行计算
if (e.lengthComputable) {
// 根据e.loaded和e.total计算进度比例
var bili = e.loaded / e.total * 100 + '%';
console.log(e);
document.getElementById('percent').style.width = bili;
document.getElementById('percent').innerText = bili;
}
};
// 设置上传文件完成的事件(更改样式)
xhr.upload.onload = function () {
document.getElementById('percent').className = 'progress-bar progress-bar-success';
}
xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar');
xhr.send(fd);
// 5 接收响应数据
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var res = JSON.parse(xhr.responseText);
// 5.1 检测上传是否成功
if (res.status === 200) {
// 5.2 将响应的图片在线地址,放入到img中展示
console.log(res);
}
}
}
};
</script>
</body>
</html>