今天的内容其实挺多的,我们慢慢来说。首先第一个是xhr的基本使用,什么是xhr?
XMLHTTPRequest是浏览器提供的js对象,可以请求服务器上的数据资源,包括我们前面一直用的jq里面的三个请求资源的方法都是基于xhr来封装的。
那么首先我们看到xhr的get请求怎么来实现
首先要创建xhr实例通过new来实现
然后调用open函数,里面值为请求方式以及url
第三步调用send函数
第四步监听onreadyStateChange事件在这个事件里面要注意一下请求状态和服务器响应状态的固定写法,还有服务器响应回的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1.创建xhr对象
var xhr = new XMLHttpRequest()
// 2.调用open函数 决定请求方式和url
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks')
// 3.调用send函数
xhr.send()
// 4.监听事件
xhr.onreadystatechange = function() {
// 4.1注意请求状态和服务器响应状态固定写法
if (xhr.readyState ==4 && xhr.status == 200) {
// 4.2获取相应的数据
console.log(xhr.response);
}
}
</script>
</body>
</html>
1
我们看到在监听请求状态变化事件里有一个readystate的属性这个属性表示ajax当前请求所处的状态,其中0表示xhr对象以创建,但请求未调用open。1表示已调用open函数。2表示已调用send函数。3表示数据接收中。最后4表示一切请求完成
那么xhr带参的get请求怎么来实现的呢?只需要在open函数的url里面接一个查询字符串即可
xhr.open(‘get’, ‘http://www.ssfddaf.com/api?name=��%gf’)
那么什么是查询字符串?
在url末尾加上?参数=值多个参数间用&来连接这就是查询字符串,无论是jQuery的三个请求方式还是xhr指定的参数其本质都是在url后带查询字符串
这里还要了解一个点url编码与解码
url中只允许出线英文不允许中文等其他语种,所以他就会把除英文外其他语种转换为%开头带两个字符的样式来代替
编码encodeURI('中文;) 解码decodeURI(%的字符)三组%表示一个中文
接下来我们看到xhr怎么发起post请求
第一步创建对象
第二部open函数把请求方式改为post
第三步设置content-type 这是一个固定写法
xhr.setRequestHeader(‘content-type’, ‘application/x-www-form-urlencoded’)
第四步调用send函数 post的参数在这里添加以查询字符串的方式添加进来
第五步监听事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1.创建xhr对象
var xhr = new XMLHttpRequest()
// 2.调用open函数
xhr.open('post', 'http://www.liulongbin.top:3006/api/addbook')
// 3.设置cententtype
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
// 4.调用send函数
xhr.send('bookname=水府传&author=我')
// 5.监听事件
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
</script>
</body>
</html>
数据交换格式
即服务器与客户端之间进行数据传输与交换的格式,XML和JSON这两种
XML我们用的比较少,它是可扩展标记语言,跟html很相似
JSON
什么事json,就是js对象和数组的字符串表示法,其中本质还是一个字符串它是轻量级文本数据交换格式
它的结构为有两种对象结构和数组结构
对象结构
‘{key:value}’咋一看跟对象很相似,但是首先外面会有引号,其次键值是字符类型必须加双引号
数组结构
【a,a】
要注意的是键值的双引号,json中不能写注释,不能使用undefined和函数作为值
json和对象互转
obj = JSON.parse(json)(反序列化)
json = JSON.stringify(obj)(序列化)
封装自己的ajax函数
①先封装一个处理data对象为查询字符串的函数
②封装函数xhr
③判断不同的请求类型达到不同的方式
这个总之记住一点就是xhr调用请求的总体步骤就没得问题
// 1.先封装函数处理传进来的参数为查询字符串
function revolveData(data) {
var arr = []
for (var k in data) {
arr[arr.length] = k + '=' + data[k]
}
var str = arr.join('&')
return str
}
// console.log(revolveData({name : '张三', age : 19}));
// 2。封装主体函数
function ajaxMine(obj) {
var xhr = new XMLHttpRequest()
var str = revolveData(obj.data)
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var res = JSON.parse(xhr.response)
obj.success(res)
}
}
// 3.判断不同的请求,做到不同的操作
if (obj.method.toUpperCase() == 'GET') {
xhr.open(obj.method, obj.url + '?' +str)
xhr.send()
} else if (obj.method.toUpperCase() == 'POST') {
xhr.open(obj.method, obj.url)
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.send(str)
}
}
验证
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./封装自己的ajax函数.js"></script>
<script>
/* ajaxMine({
method : 'get',
url : 'http://www.liulongbin.top:3006/api/getbooks',
data : {
id : 2
},
success : function(res) {
console.log(res);
}
}) */
ajaxMine({
method : 'post',
url : 'http://www.liulongbin.top:3006/api/addbook',
data : {
bookname : '收首饰',
author : '东风似旧',
publisher : '身法'
},
success : function(res) {
console.log(res);
}
})
</script>
</body>
</html>
xhr level2新特性
在我们旧版的xhr缺点就是不支持文件上传而且没有进度信息只有完没完成
在我们新版xhr
支持文件上传,有进度信息,还可以设置http时限,还可使用formdata对象管理表单数据
接下来我会一一开始xhr这四个新特性
5.1
首先第一个设置Http时限,也就是在规定时间如果还没有完成请求任务那么这个请求就失败了
xhr.timeout = 2000
与之对应的还有一个ontimeout的事件在超时后会做些什么
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest()
xhr.timeout = 50
xhr.ontimeout = function() {
console.log('请求超时了');
}
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks')
xhr.send()
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
</script>
</body>
</html>
5…2
formdata管理表单
因为我们ajax主要是用来提交表单数据的嘛,所以H5就新增了一个FormData对象用来模拟表单操作
①新建formdata对象
②为formdata添加表单项
③创建xhr
④用xhr完成请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1.创建FormData对象
var fd = new FormData()
// 2.往里面添加表单项
fd.append('uname', '王五')
fd.append('age' , 29)
// 3,创建xhr对象
var xhr = new XMLHttpRequest()
// 4.使用xhr对象制定请求类型与地址
xhr.open('post', 'http://www.liulongbin.top:3006/api/formdata')
// 5.直接提交,formdata对象,这与提交网页表单的效果完全一样
xhr.send(fd)
// 6.验证
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responsete);
}
}
</script>
</body>
</html>
formdata还有一个用法,就是可以用来获取表单的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="">
<input type="text" name="uname">
<input type="password" name="pwd">
<input type="submit" value="提交">
</form>
<script>
var form = document.querySelector('form')
form.onsubmit = e => {
e.preventDefault()
var xhr = new XMLHttpRequest()
var fd = new FormData(form)
xhr.open('post', 'http://www.liulongbin.top:3006/api/formdata')
xhr.send(fd)
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
}
</script>
</body>
</html>
5.3
上传文件
①定义UI结构
②验证是否选择了文件
③像formdata追加文件
④用xhr发起上传请求
⑤监听事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 1.定义ui结构 -->
<!-- 1.1文件选择框 -->
<input type="file">
<!-- 1.2上传按钮 -->
<input type="submit" value="上传文件">
<!-- 1.3img标签 用来显示上传成功后的图片 -->
<img src="" alt="">
<script>
// 2.验证是否上传了文件
var uploadBtn = document.querySelector('input:nth-of-type(2)')
uploadBtn.addEventListener('click', function() {
// 2.1注意这里这个。files它是一个数组存放的是文件
let files = document.querySelector('input:first-child').files
if (files.length > 0) {
// 3.像formdata中追加文件
var fd = new FormData()
// avator为头像假装这里是上传的头像
fd.append('avatar', files[0])
// 4.使用xhr发起上传文件请求
var xhr = new XMLHttpRequest()
xhr.open('post', 'http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd)
// 5.监听事件
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
// console.log(xhr.responseText);
let imgData = JSON.parse(xhr.responseText)
if (imgData.status == 200) {
document.querySelector('img').src = 'http://www.liulongbin.top:3006' + imgData.url
} else {
console.log('上传文件失败');
}
}
}
} else {
return alert('请上传文件')
}
})
</script>
</body>
</html>
5.4
显示上传进度
通过xhr.upload.onprogress事件来监听这里面有三个属性值得注意一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 1.定义ui结构 -->
<!-- 1.1文件选择框 -->
<input type="file">
<!-- 1.2上传按钮 -->
<input type="submit" value="上传文件">
<!-- 1.3img标签 用来显示上传成功后的图片 -->
<img src="" alt="">
<script>
// 2.验证是否上传了文件
var uploadBtn = document.querySelector('input:nth-of-type(2)')
uploadBtn.addEventListener('click', function() {
// 2.1注意这里这个。files它是一个数组存放的是文件
let files = document.querySelector('input:first-child').files
if (files.length > 0) {
// 3.像formdata中追加文件
var fd = new FormData()
// avator为头像假装这里是上传的头像
fd.append('avatar', files[0])
// 4.使用xhr发起上传文件请求
var xhr = new XMLHttpRequest()
// --------------------------------
// 1.上传进度监听事件
xhr.upload.onprogress = e => {
// 2.参数一 e.lengthComputable是一个布尔值,表示当前上传的资源是否具有可计算的长度要有才能进去
if (e.lengthComputable) {
// 参数二e.loaded已传输的字节
// 参数三e.total需传输的总字节
var percenComplete = Math.ceil((e.loaded / e.total) * 100)
console.log(percenComplete);
}
}
xhr.open('post', 'http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd)
// 5.监听事件
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
// console.log(xhr.responseText);
let imgData = JSON.parse(xhr.responseText)
if (imgData.status == 200) {
document.querySelector('img').src = 'http://www.liulongbin.top:3006' + imgData.url
} else {
console.log('上传文件失败');
}
}
}
} else {
return alert('请上传文件')
}
})
</script>
</body>
</html>
知道了上传进度我们就可以通过bootstrap来一个进度条板的上传进度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../day01/lib/bootstrap.css">
</head>
<body>
<!-- 1.定义ui结构 -->
<!-- 1.1文件选择框 -->
<input type="file">
<!-- 1.2上传按钮 -->
<input type="submit" value="上传文件">
<!-- 1.3img标签 用来显示上传成功后的图片 -->
<img src="" alt="">
<!-- 进度条 -->
<div class="progress" >
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" >
0%
</div>
</div>
<script>
// 2.验证是否上传了文件
var uploadBtn = document.querySelector('input:nth-of-type(2)')
uploadBtn.addEventListener('click', function() {
// 2.1注意这里这个。files它是一个数组存放的是文件
let files = document.querySelector('input:first-child').files
if (files.length > 0) {
// 3.像formdata中追加文件
var fd = new FormData()
// avator为头像假装这里是上传的头像
fd.append('avatar', files[0])
// 4.使用xhr发起上传文件请求
var xhr = new XMLHttpRequest()
// --------------------------------
// 1.监听事件
var program = document.querySelector('.progress-bar')
xhr.upload.onprogress = e => {
// 2.参数一 e.lengthComputable是一个布尔值,表示当前上传的资源是否具有可计算的长度要有才能进去
if (e.lengthComputable) {
// 参数二e.loaded已传输的字节
// 参数三e.total需传输的总字节
var percenComplete = Math.ceil((e.loaded / e.total) * 100)
// console.log(percenComplete);
program.style.width = percenComplete + '%'
program.innerText = '%' + percenComplete
}
}
xhr.open('post', 'http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd)
// 5.监听事件
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
// console.log(xhr.responseText);
let imgData = JSON.parse(xhr.responseText)
if (imgData.status == 200) {
document.querySelector('img').src = 'http://www.liulongbin.top:3006' + imgData.url
} else {
console.log('上传文件失败');
}
}
}
} else {
return alert('请上传文件')
}
})
</script>
</body>
</html>
最后完善上传成功的进度条
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../day01/lib/bootstrap.css">
</head>
<body>
<!-- 1.定义ui结构 -->
<!-- 1.1文件选择框 -->
<input type="file">
<!-- 1.2上传按钮 -->
<input type="submit" value="上传文件">
<!-- 1.3img标签 用来显示上传成功后的图片 -->
<img src="" alt="">
<!-- 进度条 -->
<div class="progress" >
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" >
0%
</div>
</div>
<script>
// 2.验证是否上传了文件
var uploadBtn = document.querySelector('input:nth-of-type(2)')
uploadBtn.addEventListener('click', function() {
// 2.1注意这里这个。files它是一个数组存放的是文件
let files = document.querySelector('input:first-child').files
if (files.length > 0) {
// 3.像formdata中追加文件
var fd = new FormData()
// avator为头像假装这里是上传的头像
fd.append('avatar', files[0])
// 4.使用xhr发起上传文件请求
var xhr = new XMLHttpRequest()
// --------------------------------
// 1.监听事件
var program = document.querySelector('.progress-bar')
xhr.upload.onprogress = e => {
// 2.参数一 e.lengthComputable是一个布尔值,表示当前上传的资源是否具有可计算的长度要有才能进去
if (e.lengthComputable) {
// 参数二e.loaded已传输的字节
// 参数三e.total需传输的总字节
var percenComplete = Math.ceil((e.loaded / e.total) * 100)
// console.log(percenComplete);
program.style.width = percenComplete + '%'
program.innerText = '%' + percenComplete
}
}
// -----------------------------------
// 2.上传成功进度条变化
xhr.upload.onload = () => {
program.className = ''
program.className = 'progress-bar progress-bar-success'
}
xhr.open('post', 'http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd)
// 5.监听事件
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
// console.log(xhr.responseText);
let imgData = JSON.parse(xhr.responseText)
if (imgData.status == 200) {
document.querySelector('img').src = 'http://www.liulongbin.top:3006' + imgData.url
} else {
console.log('上传文件失败');
}
}
}
} else {
return alert('请上传文件')
}
})
</script>
</body>
</html>
jQuery高级用法
用jq来实现文件上传
①定义ui结构和前面一样
②验证是否选择文件
③向formdata追加文件
④使用jq发起上传请求
⑤jq实现loading效果 两个方法一检测到任何ajax开始或失败就会调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 1.定义UI结构 -->
<form action="">
<input type="file" name="file" id="">
</form>
<!-- 这里出现了一点小问题 我在后面打印res始终打印不出来而且反正就想数据被清了一下思来想去才知道是我把button放在表单里了所以一点击就会造成默认行为 -->
<button type="submit">上传图片</button>
<img src="../../../../HTML/04-阶段四 前后端交互/第四阶段:前后端交互阶段资料新/ajax课程资料/day3(7-12小节)/code/images/loading.gif" alt="">
<script src="../day01/lib/jquery.js"></script>
<script>
// 5.这个方法是侦听到所有的ajax请求就会开始执行
$(document).ajaxStart(function() {
$('img').show()
})
$(document).ajaxStop(function() {
$('img').hide()
})
// 2.验证是否选择了文件
$('button').on('click', function() {
// 这里需要将jq对象转为原生dom对象来使用files这个属性
var files = $('input')[0].files
// console.log(files);
if (files.length <= 0) {
return alert('请选择文件')
} else {
// 3.向formdata追加文件
var fd = new FormData()
fd.append('avatar', files[0])
// 4.利用jq来发起上传请求
$.ajax({
method: 'POST',
url: 'http://www.liulongbin.top:3006/api/upload/avatar',
data: fd,
processData: false,
contentType: false,
success: function (res) {
console.log(res)
}
})
}
})
</script>
</body>
</html>
axios
今天的最后一个内容,什么事axios,专注于网络数据请求的库,相比于原生xhr更简单易用,相比于jq更轻量化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./axios.js"></script>
</head>
<body>
<button>发起get请求</button>
<script>
var btn = document.querySelector('button')
/* btn.onclick = function() {
var url = 'http://www.liulongbin.top:3006/api/get'
var obj = {name : '张三', age : 29}
axios.get(url, {params: obj}).then(function(res) {
console.log(res);
})
} */
btn.onclick = () => {
axios({
method : 'get',
url : 'http://www.liulongbin.top:3006/api/get',
params : {name : '张三', age : 29}
}).then(res => console.log(res))
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./axios.js"></script>
</head>
<body>
<button>发起post请求</button>
<script>
/* document.querySelector('button').onclick =function() {
var url = 'http://www.liulongbin.top:3006/api/post'
var obj = {location : '重庆', address : '江北'}
axios.post(url, {obj}).then(res => console.log(res))
} */
document.querySelector('button').onclick = () => {
axios({
method : 'post',
url : 'http://www.liulongbin.top:3006/api/post',
data : {name : '张三', age : 29}
}).then(res => console.log(res))
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../day01/lib/bootstrap.css">
</head>
<body>
<!-- 1.定义ui结构 -->
<!-- 1.1文件选择框 -->
<input type="file">
<!-- 1.2上传按钮 -->
<input type="submit" value="上传文件">
<!-- 1.3img标签 用来显示上传成功后的图片 -->
<img src="" alt="">
<!-- 进度条 -->
<div class="progress" >
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" >
0%
</div>
</div>
<script>
// 2.验证是否上传了文件
var uploadBtn = document.querySelector('input:nth-of-type(2)')
uploadBtn.addEventListener('click', function() {
// 2.1注意这里这个。files它是一个数组存放的是文件
let files = document.querySelector('input:first-child').files
if (files.length > 0) {
// 3.像formdata中追加文件
var fd = new FormData()
// avator为头像假装这里是上传的头像
fd.append('avatar', files[0])
// 4.使用xhr发起上传文件请求
var xhr = new XMLHttpRequest()
// --------------------------------
// 1.监听事件
var program = document.querySelector('.progress-bar')
xhr.upload.onprogress = e => {
// 2.参数一 e.lengthComputable是一个布尔值,表示当前上传的资源是否具有可计算的长度要有才能进去
if (e.lengthComputable) {
// 参数二e.loaded已传输的字节
// 参数三e.total需传输的总字节
var percenComplete = Math.ceil((e.loaded / e.total) * 100)
// console.log(percenComplete);
program.style.width = percenComplete + '%'
program.innerText = '%' + percenComplete
}
}
// -----------------------------------
// 2.上传成功进度条变化
xhr.upload.onload = () => {
program.className = ''
program.className = 'progress-bar progress-bar-success'
}
xhr.open('post', 'http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd)
// 5.监听事件
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
// console.log(xhr.responseText);
let imgData = JSON.parse(xhr.responseText)
if (imgData.status == 200) {
document.querySelector('img').src = 'http://www.liulongbin.top:3006' + imgData.url
} else {
console.log('上传文件失败');
}
}
}
} else {
return alert('请上传文件')
}
})
</script>
</body>
</html>