前言
最近碰到要给需求,需要做一个上传进度的进度,附加一个进度动画,摸索了好久,终于用原生的XMLHTTPREQUEST和axios以及jQuery实现了,下面就是代码
HTML
<div>
<div class="downloadContainer">
<div class="animateImgWrapper">
<img class="animateImg" src="./1.jpg" alt=""/>
</div>
<div class="animateBarWrapper">
<div class="animateBar"></div>
</div>
<div>
<p class="upload">文件上传</p>
<input class="file" type="file" name="file"/>
</div>
<div>
<input class="submit" type="submit" value="提交"/>
</div>
</div>
</div>
CSS
html,
body {
margin: 0;
padding: 0;
}
.animateImgWrapper {
height: 30px;
}
img {
width: 30px;
height: 30px;
border-radius: 50%;
display: none;
}
.animateBarWrapper {
height: 5px;
width: 100%;
background-color: #d8e5f4;
}
.animateBar {
height: 5px;
width: 0;
line-height: 30px;
text-align: center;
background-color: #5287ee;
}
.file {
display: none;
}
.fileShow {
display: block;
background: #5287ee;
}
.imgShow {
display: block;
}
js
xhr
const animateImgWrapper = document.querySelector(".animateImgWrapper");
const upload = document.querySelector(".upload");
const file = document.querySelector(".file");
const submit = document.querySelector(".submit");
const animateImg = document.querySelector(".animateImg");
const animateBar = document.querySelector(".animateBar");
upload.addEventListener("click", function () {
file.click();
});
file.addEventListener("change", function (e) {
file.classList.add("fileShow");
});
submit.addEventListener("click", function () {
if (file.files[0] == null) {
alert("请先上传文件");
} else {
const f = file.files[0];
const name = file.files[0].name;
const options = {
f,
name,
};
xhr(options)
}
});
// 文件上传
function xhr(options) {
const formData = new FormData();
const Rect = animateImgWrapper.getBoundingClientRect();
let defaults = {
method: "post",
url: "http://localhost:8088/upload/file?userid=gsgsgsgsg",
};
defaults = Object.assign(defaults, options);
formData.append("file", defaults.f, defaults.name);
const xhr = new XMLHttpRequest();
xhr.open(defaults.method, defaults.url);
// 上传的返回结果
xhr.onloadend = function (e) {
if (xhr.status == 200) {
animateImg.style.display = "none";
}
};
// 文件上传进度
xhr.upload.addEventListener("progress", (e) => {
animateImg.style.display = "block";
let result = e.loaded / e.total;
let move = result * Rect.width - 30 + "px";
animateImg.style.transform = `translateX(${move})`
/* animateImg.animate(
[
{
transform: `translateX(${move})`,
},
],
{
easing: "ease",
fill: "forwards",
duration: 250
}
);*/
// 下面的进度条
animateBar.style.width = `${result * 100}%`;
animateBar.innerHTML = parseInt(String(result * 100)) + "%";
});
xhr.send(formData);
}
/*
// 最快250ms触发一次
function throttle (func, limit = 250) {
let inThrottle = false;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}*/
jquery
const animateImgWrapper = document.querySelector(".animateImgWrapper");
const upload = document.querySelector(".upload");
const file = document.querySelector(".file");
const submit = document.querySelector(".submit");
const animateImg = document.querySelector(".animateImg");
const animateBar = document.querySelector(".animateBar");
upload.addEventListener("click", function () {
file.click();
});
file.addEventListener("change", function (e) {
file.classList.add("fileShow");
});
submit.addEventListener("click", function () {
if (file.files[0] == null) {
alert("请先上传文件");
} else {
const f = file.files[0];
const name = file.files[0].name;
const options = {
f,
name,
};
xhr(options)
}
});
// 文件上传
function xhr(options) {
const formData = new FormData();
const Rect = animateImgWrapper.getBoundingClientRect();
let defaults = {
method: "post",
url: "http://localhost:8088/upload/file?userid=gsgsgsgsg",
};
defaults = Object.assign(defaults, options);
formData.append("file", defaults.f, defaults.name);
$.ajax({
url: defaults.url,
type: defaults.method,
data: formData,
contentType: false,//必须false才会自动加上正确的Content-Type
processData: false,//必须false才会避开jQuery对 formdata 的默认处理
xhr: function () { //获取ajaxSettings中的xhr对象,为它的upload属性绑定progress事件的处理函数
myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) { //检查upload属性是否存在
//绑定progress事件的回调函数
myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
}
return myXhr; //xhr对象返回给jQuery使用
},
success: function (data) {
console.log("做一些事情吧")
},
error: function () {
mui.alert("上传失败!", "提示", "确定");
}
});
}
axios
使用axios不需要用formdata对文件进行处理,axios自己内部会处理
const formdata = new FormData()
formdata.append("file",this.files[0],this.files[0].name)
this.axios.post(uploadUrl, formdata , {
headers: {
'Content-Type': 'multipart/form-data'
},
transformRequest: [function (data) {
return data
}],
onUploadProgress: progressEvent => {
let complete = (progressEvent.loaded / progressEvent.total * 100 | 0) + '%'
self.uploadMessage = '上传 ' + complete
}
})
.then((response) => {
if (response.status === 200) {
self.uploadMessage = '上传成功!'
}
})
注意事项
使用ajax和或者原生的xhr上传时,千万不用设置请求头'Content-Type': 'multipart/form-data',不然后台使用 org.springframework.web.multipart.MultipartFile类时无法拿到传过去的file的值,值总是为null,这也是我自己搞了好久才找到的知识点,但是使用axios时,就必须指定了,xhr和ajax不行,好像是chrome自己会做一层转换,具体原因忘了记下了,总之就是不能设置请求头,另外这个图片跟着进度条走的时候,还有优化空间,可以让他看起来跟丝滑参考,但是我自己试了下,效果不是太好,但是这完全是我自己没有处理好,该demo后续会继续完善