旧版XMLHttpRequest的缺点
1、只支持文本数据的传输,无法用来读取和上传文件
2、传送和接收数据时,没有进度信息,只能提示有没有完成
XMLHttpRequest Level2的新功能
1、可以设置HTTP请求的时限
有时Ajax操作很耗时,而且无法预知要花多少时间,如果网速很慢,用户可能要等很久,新版本的XMLHttpRequest对象增加了 timeout属性,可以设置HTTP请求的时限:
xhr.timeout = 3000
xhr.ontimeout = function(event){
alert('请求超时!')
}
上面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动停止HTTP请求。与之配套的还有一个timeout 事件 用来指定回调函数
2、可以使用FormData对象管理表单数据
Ajax操作往往用来提交表单数据。为了方便表单处理,HTML5新增了一个FormData对象,
可以模拟表单
// 新建FormData 对象
let fd = new FormData()
// 为FormData 添加表单项
fd.append('uname','吴大友')
fd.append('upwd','123456')
//1、创建xhr对象
let xhr2 = new XMLHttpRequest()
//2、调用open函数 指定请求方式和URL地址
xhr2.open('POST','http://www.liulongbin.top:3006/api/formdata')
//3、设置Content-Type 属性(固定写法)
xhr2.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
//3、调用send函数 发起Ajax 请求 同时将数据以查询字符串的形式 发送给服务器
// 直接提交form 对象 这与提交网页表单的效果 完全一样
xhr2.send(fd)
//4、 监听onreadystatechange 事件
xhr2.onreadystatechange = function () {
// 4.1 监听xhr 对象的请求状态 readyState 和服务器的相应状态 status 固定写法 这里的status 和 res 返回的不是同一个
if (xhr2.readyState === 4 && xhr2.status === 200){
// 4.2 打印服务器相应回来的数据 responseText
let res = JSON.parse(xhr2.responseText)
//JSON.parse() 将JSON字符 转换成 对象数据
console.log(res)
}
}
也可以用来获取网页表单的值
// 获取表单元素
let form1 = document.querySelector('#form1')
// 监听表单的submit事件
form1.addEventListener('submit',function (e) {
e.preventDefault()
// 根据form 表单创建 FormData 对象,会自动将表单数据填充到FormData 对象种
let fd1 = new FormData(form1)
// xhr 剩下步骤
let xhr3 = new XMLHttpRequest()
xhr3.open('POST','http://www.liulongbin.top:3006/api/formdata')
//3、设置Content-Type 属性(固定写法)
xhr3.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
//3、调用send函数 发起Ajax 请求 同时将数据以查询字符串的形式 发送给服务器
// 直接提交form 对象 这与提交网页表单的效果 完全一样
xhr3.send(fd1)
//4、 监听onreadystatechange 事件
xhr3.onreadystatechange = function () {
// 4.1 监听xhr 对象的请求状态 readyState 和服务器的相应状态 status 固定写法 这里的status 和 res 返回的不是同一个
if (xhr3.readyState === 4 && xhr3.status === 200){
// 4.2 打印服务器相应回来的数据 responseText
let res = JSON.parse(xhr3.responseText)
//JSON.parse() 将JSON字符 转换成 对象数据
console.log(res)
}
}
})
3、可以上传文件 并且 获得数据传输的进度信息
实现步骤:
- 定义UI结构
- 验证是否选择了文件
- 向FormData中追加文件
- 使用xhr发起上传文件的请求- xhr.upload.onprogress 事件计算返回进度的百分比,运用合适的组件库渲染到页面上(这里用的是bootstrap)
- 监听onreadystatechange事件-完成后移除上传过程与用的样式,添加上传完成时用的样式
UI结构
选择按钮和提交按钮
<div>
<input type="file" id="file1" value="选择图片">
<button id="btn">上传图片</button>
</div>
进度条显示区域
<div class="progress" style="width: 500px;display: none">
<div class="progress-bar progress-bar-striped active" style="width: 0%" id="plan">
</div>
</div>
图片展示区域 上传完成后为此元素增加 src 属性
<img src="" alt="" id="img" width="800" style="display: block">
script:
let btn = document.querySelector('button')
btn.addEventListener('click',function () {
let files = document.querySelector('#file1').files
if (files.length <= 0){
alert('没有选择文件、请重新选择')
return
}
$('.progress').css('display','block')
let fd = new FormData()
fd.append('avatar',files[0])
let xhr = new XMLHttpRequest()
// 监听 xhr.upload 的 onprogress 事件
xhr.upload.onprogress = function(e){
// e.lengthComputable 是一个布尔值 表示当前上传的资源是否具有可计算的长度
if (e.lengthComputable){
// e.loaded 已经传输的字节 e.total 需要传输的总字节
let schedule = Math.ceil((e.loaded / e.total) * 100)
// 赋值更新进度条的宽度和百分比
$('#plan').attr('style','width:'+schedule+'%').html(schedule+'%')
}
}
xhr.upload.onload = function(){
$('#plan').removeClass().addClass('progress-bar progress-bar-success')
setTimeout(function () {
$('.progress').css('display','none')
},250)
}
xhr.open('POST','http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200){
let data = JSON.parse(xhr.responseText)
if (data.status === 200){ // 内部再判断一下 因为和外面的 status 不是同一个
// 将置留的img 加上src
let img = document.querySelector('#img')
img.src = 'http://www.liulongbin.top:3006'+data.url
}else {
console.log(data.message)
}
}
}
})
依赖的资源:
<script src="http://www.wsg3096.com/ass/jquery-3.6.0.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
使用jquery简化文件上传
jquery使用Ajax上传文件时
只需要添加配置
// 不修改content-Type 属性 使用FormData 默认的Content-Type值
contentType:false,
// 不对FormData 中的数据进行url 编码 而是将FormData 原样数据发送到服务器
processData:false,
并且运用ajaxStart ajaxStop 两个回调函数 进行等待图片的显示和隐藏操作
$(document).ajaxStart(function () {
$('#load').fadeIn()
})
$(document).ajaxStop(function () {
$('#load').fadeOut()
})
完成代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>17jQuery简化文件上传</title>
<script src="http://www.wsg3096.com/ass/jquery-3.6.0.js"></script>
<style>
#load{
position: absolute;
transform: translate(-50%,-50%);
}
</style>
</head>
<body>
<input type="file" id="file1">
<button>上传</button>
<img src="" alt="" style="display: block" id="wsg">
<img src="pic/load.gif" alt="" style="max-width: 360px;display: none" id="load">
<img src="pic/jquery-upload.jpg" alt="" style="display: block">
<script>
$('button').on('click',function () {
// [0] 转化成dom 对象
let files = $('#file1')[0].files
if (files.length<= 0){
alert('请选择文件后再上传')
return
}else {
let fd = new FormData()
fd.append('avatar',files[0])
$.ajax({
method:'POST',
url:'http://www.liulongbin.top:3006/api/upload/avatar',
data:fd,
// 不修改content-Type 属性 使用FormData 默认的Content-Type值
contentType:false,
// 不对FormData 中的数据进行url 编码 而是将FormData 原样数据发送到服务器
processData:false,
success:function (res) {
console.log(res)
let url = 'http://www.liulongbin.top:3006'+res.url
$('#wsg').prop('src',url)
}
})
}
})
$(document).ajaxStart(function () {
$('#load').fadeIn()
})
$(document).ajaxStop(function () {
$('#load').fadeOut()
})
</script>
</body>
</html>