在以往的项目,用过三种方式的文件上传,分别是xhr、webuploader、plupload,好记性不如烂笔头,在开始整理笔记的时候,文件上传的优先级就排得敲级高,毕竟特别常用嘛~表达能力有限,只能无限开门放代码。。。
xhr
这个方法的兼容性不太好。
XMLHttpRequest一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个接口,再后来W3C对它进行了标准化,提出了XMLHttpRequest标准。XMLHttpRequest标准又分为Level 1和Level 2。
XMLHttpRequest Level 1主要存在以下缺点:
受同源策略的限制,不能发送跨域请求;
不能发送二进制文件(如图片、视频、音频等),只能发送纯文本数据;
在发送和获取数据的过程中,无法实时获取进度信息,只能判断是否完成;Level 2对Level 1 进行了改进,XMLHttpRequest Level 2中新增了以下功能:
可以发送跨域请求,在服务端允许的情况下;
支持发送和接收二进制数据;
新增formData对象,支持发送表单数据;
发送和获取数据时,可以获取进度信息;
可以设置请求的超时时间;
图片是XmlHttpRequest Level 2的兼容性
从图中可以看到:
IE8/IE9、Opera Mini 完全不支持xhr对象
IE10/IE11部分支持,不支持 xhr.responseType为json
部分浏览器不支持设置请求超时,即无法使用xhr.timeout
部分浏览器不支持xhr.responseType为blob
以上xhr兼容性描述是引用自https://segmentfault.com/a/11...
以下是我之前写的有进度条的文件上传的demo,里面有css样式,代码比较长。通过给xhr对象添加监听事件,比如beforeSend事件初始化进度条,progress事件返回上传进度等。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name=”renderer” content="webkit|ie-comp|ie-stand">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>运单上传</title>
<style>
html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
}
body {
background: #b4e1f4;
position: relative;
font-family: '微软雅黑';
}
.upload-cont {
height: 270px;
width: 500px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
background: #f5f1e8;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-moz-box-shadow: 1px 1px 10px #888888;
-webkit-box-shadow: 1px 1px 10px #888888;
box-shadow: 1px 1px 10px #888888;
}
.upload-title {
height: 60px;
line-height: 60px;
color: #fff;
font-size: 18px;
padding-left: 20px;
background: -moz-linear-gradient(top, #ee8f57 0%, #ea7047 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ee8f57), color-stop(100%,#ea7047));
background: -webkit-linear-gradient(top, #ee8f57 0%,#ea7047 100%);
background: -o-linear-gradient(top, #ee8f57 0%,#ea7047 100%);
background: -ms-linear-gradient(top, #ee8f57 0%,#ea7047 100%);
background: linear-gradient(to bottom, #ee8f57 0%,#ea7047 100%);
-webkit-border-top-left-radius: 5px;
-moz-border-radius-topleft: 5px;
border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-topright: 5px;
border-top-right-radius: 5px;
}
.upload-form {
padding: 15px 20px;
}
.upload-hint {
color: #48b8e0;
}
.file-cont {
width: 325px;
height: 38px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
border: 1px solid #d3d3d3;
vertical-align: middle;
margin: 20px 0;
padding: 0 10px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.select-btn {
position: relative;
display: inline-block;
vertical-align: middle;
margin: 20px 0 20px 5px;
}
.select-btn input[type=file] {
width: 100px;
height: 40px;
position: relative;
z-index: 9;
opacity: 0;
cursor: pointer;
}
.select-btn label {
position: absolute;
display: inline-block;
color: #fff;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
top: 0;
left: 0;
background: #ea7047;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.cut-line {
border-top: 1px solid #d3d3d3;
}
.progress-bar {
height: 22px;
width: 345px;
margin-top: 18px;
display: inline-block;
position: relative;
border: 1px solid #d3d3d3;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow:1px 1px 8px #888888 inset;
-webkit-box-shadow:1px 1px 8px #888888 inset;
box-shadow:1px 1px 8px #888888 inset;
}
.progress-bar-inner {
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 22px;
text-align: center;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background: -moz-linear-gradient(top, #ee8f57 0%, #ea7047 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ee8f57), color-stop(100%,#ea7047));
background: -webkit-linear-gradient(top, #ee8f57 0%,#ea7047 100%);
background: -o-linear-gradient(top, #ee8f57 0%,#ea7047 100%);
background: -ms-linear-gradient(top, #ee8f57 0%,#ea7047 100%);
background: linear-gradient(to bottom, #ee8f57 0%,#ea7047 100%);
}
.upload-btn {
width: 100px;
height: 40px;
margin-top: 10px;
background: #48b8e0;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
border: none;
color: #fff;
font-size: 16px;
cursor: pointer;
float: right;
}
.mask-bg {
position: absolute;
top: 0;
background: #000;
opacity: 0.3;
width: 100%;
height: 100%;
z-index: 1000;
}
.hint-cont {
z-index: 1100;
background: #fff;
width: 300px;
height: 120px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
text-align: center;
border-radius: 5px;
}
.hint-title {
display: inline-block;
height: 40px;
line-height: 40px;
}
.hint-close {
float: right;
margin-right: 10px;
font-size: 25px;
cursor: pointer;
}
.hint-content {
margin-top: 10px;
}
</style>
</head>
<body>
<div class="upload-cont">
<div class="upload-title">上传文件</div>
<form id= "uploadForm" class="upload-form">
<div class="upload-hint">提示:请上传excel文件</div>
<div>
<input type="text" class="file-cont" disabled>
<div class="select-btn">
<input id="fileUpload" type="file" name="file"/>
<label>选择文件</label>
</div>
</div>
<hr class="cut-line">
<div id="progressBar" class="progress-bar">
<div class="progress-bar-inner"></div>
</div>
<input type="button" value="上传" class="upload-btn" onclick="doUpload()" />
</form>
<!----------------------------------->
<br>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
var resultData;
function doUpload(){
var formData = new FormData($( "#uploadForm" )[0]);
var xhr = new XMLHttpRequest();
// 上传前初始化
xhr.addEventListener('beforeSend', function () {
$('.progress-bar-inner').css('width', '0%').text('');
});
//上传中设置上传的百分比
xhr.upload.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
$('.progress-bar-inner').css('width', percentComplete+"%").text(percentComplete+"%");
}else {
$('#progressBar').text('无法计算');
}
}, false);
//请求完成后执行的操作
xhr.addEventListener("load", function(evt){
var message = evt.target.responseText, obj = eval("("+message+")");
if(obj.status == 1){
showHintDialog(evt);
}else{
showHintDialog(obj.message);
}
}, false);
//请求error
xhr.addEventListener("error", uploadFailed, false);
//请求中断
xhr.addEventListener("abort", uploadCanceled, false);
//发送请求
xhr.open("POST", "../excel/in/");
xhr.send(formData);
function uploadFailed(evt) {
showHintDialog("上传出错");
}
function uploadCanceled(evt) {
showHintDialog("上传已由用户或浏览器取消删除连接");
}
}
function showHintDialog (str) {
var urlHtml;
if (typeof str == 'object') {
if(!str.success) {
if (str.errorMessage.startsWith('http')) {
urlHtml = '<a href=" ' + str.errorMessage + '"onclick="closeHint()" target="_blank" style="color:red">有错误运单数据,请点击下载</a>';
} else {
urlHtml = '<p style="color: red">' + str.errorMessage + '</p>';
}
}else{
urlHtml = '<p style="color: black">文件上传成功 </p>';
}
}
var dialogHtml = '<div id="alertStrCont"><div class="mask-bg" onclick="closeHint()"></div><div class="hint-cont"><span class="hint-title">提示</span><span class="hint-close" onclick="closeHint()">×</span><div class="hint-content">'+urlHtml+'</div></div></div>';
$('body').append(dialogHtml);
}
function closeHint() {
$('#alertStrCont').remove();
}
$('#fileUpload').on('change', function () {
if (this.files.length === 0) { return; }
var oFile = this.files[0];
$('.file-cont').val(oFile.name);
})
</script>
</body>
</html>
补充:有用xhr做过图片直传七牛。用canvas压缩了图片,该方法还是不兼容IE8,是用appcan做一个小项目的时候用过。附上代码。(需求是多图片上传,需要一张一张上传,并且如果有其中一张图片在上传时失败,则停止上传剩下的图片,如果全部上传成功,则提交整个表单,submitDone()方法就是提交表单,因为与本文没什么关系,就不写出来了。)
function putb64(dataArr) {
var pic = dataArr[isSuc].substring(23); // pic是图片的base64编码
var timestamp = (new Date()).valueOf();
var url = "http://upload.qiniu.com/putb64/-1";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.setRequestHeader("Authorization", "UpToken " + $("input[name=token]").val());
xhr.send(pic);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
var data = $.parseJSON(xhr.responseText);
key.push(data.key); ++isSuc;
if (isSuc < baseArr.length) {
putb64(dataArr);
} else if (isSuc == baseArr.length) {
submitDone();
}
} else {
appcan.window.alert({
title : '',
content : xhr.responseText,
buttons : '确定'
});
stopLoading();
toast('图片上传失败');
}
}
}
}
附上图片转base64编码方法
var img = new Image();
img.src = imgArr[imgIndex]; //imgArr是图片数组
img.onload = function() {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/jpeg", 0.4); // 0.4就是图片压缩的程度
baseArr.push(dataURL);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。