通过jquery的ajax异步上传文件,使用FormData 对象提交数据,使用xhr显示上传进度条。
主要用于:批量上传图片,上传文件数据,也可用于异步提交数据,而独立于表单使用。
这篇文章主要讲述,批量上传txt的文件,图片类似。
<form action='sc.php' method="post" enctype="multipart/form-data" >
<input type="file" name="ycfile" id="ycfile" multiple="multiple" accept="text/plain"/>
<input type="button" value="上传" id="shangchuan"/>
<div style="width:600px;height:auto;border:1px solid red;" id="zhanshi">
</div>
</form>
2.导入jquery库,写一个input的change事件,申明一个全局变量i,每张上传文件对应一个数字,一个全局变量data,格式为formdata对象,使用formdata提交数据。
此处可以使用append追加数据,但是append我不知道怎么删除列表中的单独一个元素
var i=0;
var data = new FormData();
$("#ycfile").change(function(){
var files = $(this).prop('files');
$.each(files,function(index,value){
// 使用formdata的set函数,对上传的文件进行保存
data.set('myfile_'+i, value);
var html = '+i+'">+i+'">'+value.name+'+i+'">0%+i+'" style="background:#428bca;width:0px;height:10px" >+i+'" class="progresssc" scid="'+i+'">删除';
i = i+1;
//在此处可以做上传图片预览,因为我上传的是txt文件,所以只是展示,做一个删除功能
$("#zhanshi").append(html);
})
});
3.点击上传按钮,对每个formdata中的对象逐个异步上传,注意点击按钮直接提交表单。
formdata知识点:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/values
$("#shangchuan").click(function(){
if (!data) {
alert("请上传文件");
return false;
}
var upload_data = data;
//点击上传就清空data数据
data = new FormData();
for (var key of upload_data.keys()) {
if(key && upload_data.get(key)) {
shangchuan(key,upload_data.get(key))
}
}
});
4.异步进行上传文件数据,然后显示进度条
function shangchuan(key,value)
{
//截图key后面的数字
var index = key.split("_").pop();
var ext = value.name.split(".").pop();
console.log(key+"来了");
//console.log(value);
if(ext !== "txt") {
$("#hezi_"+index).append("上传失败:上传的文件类型不正确");
return key;
}
if(value.type !== "text/plain") {
$("#hezi_"+index).append("上传失败:上传的文件类型不正确");
return key;
}
if ((value.size/1024)>(10*1024)) {
$("#hezi_"+index).append("上传失败:上传的文件大小为10M");
return key;
}
var formData = new FormData();
formData.append("wenjian",value)
$.ajax({
url: 'sc.php',
type: 'POST',
data: formData,
cache: false,
processData: false,
contentType: false,
dataType:'json',
xhr: function () {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function (e) {
//外部资源加载过程中触发,默认500毫秒。
//loaded代表上传了多少
//total代表总数为多少
var progressRate = Math.round((e.loaded / e.total) * 100,-2) + '%';
//console.log(progressRate);
//通过设置进度条的宽度达到效果
$("#percent_"+index).html(progressRate)
$("#progressnumber_"+index).css("width",progressRate);
})
xhr.upload.addEventListener('load', function (e) {
//外部资源加载成功时触发。如果后台处理时间过长,可以在此提示“后台正在处理请稍等”
})
return xhr;
},
success: function (res) {
if(res.status=='fail') {
console.log("失败了");
$("#hezi_"+index).append("上传失败:"+ res.msg +"");
}else if(res.status=='success'){
$("#shanchu_"+index).remove();
$("#hezi_"+index).children('.shibai_tishi').remove();
console.log(res.data);
//可以把返回的上传路径展示在页面中
}else {
$("#hezi_"+index).append("上传失败:未知原因");
}
return key;
}
});
}
5.对上传失败的文件进行删除,因为展示代码是jquery追加的,所以需要用on绑定事件
此处大家可以考虑一下,怎么使用FormData.delete(),删除append 追加的指定任意元素
$("#zhanshi").on("click",".progresssc",function () {
//删除准备上传的文件
var id = $(this).attr("scid")
data.delete("myfile_"+id);
$(this).parent("div").remove();
});
6.php代码处理上传的文件,返回json格式的数据
此处有个问题,就是上传的文件超过php的max_upload设置,直接报错了,这样ajax就没法判返回结果了,要不然再处理结果的时候写个else ,我屏蔽以后没效果,不知道是不是我本地环境的问题.
exit(json_encode(['status'=>'fail',"msg"=>"后缀不正确","data"=>""]));
exit(json_encode(['status'=>'success',"msg"=>"成功","data"=>trim($upload_path.$file_name)]));
7.全部源码
<!DOCTYPE html>
<head>
<meta charset=utf-8><meta name=referrer content=always><meta http-equiv=x-dns-prefetch-control content=on><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1">
<script type="text/javascript" src="jquery-1.7.2.min.js"></script>
<title>上传</title>
</head>
<body>
<form action='sc.php' method="post" enctype="multipart/form-data" >
<input type="file" name="ycfile" id="ycfile" multiple="multiple" accept="text/plain"/>
<input type="button" value="上传" id="shangchuan"/>
<div style="width:600px;height:auto;border:1px solid red;" id="zhanshi">
</div>
</form>
<script>
$(function(){
var i=0;
var data = new FormData();
$("#ycfile").change(function(){
var files = $(this).prop('files');
$.each(files,function(index,value){
data.set('myfile_'+i, value);
var html = '+i+'">+i+'">'+value.name+'+i+'">0%+i+'" style="background:#428bca;width:0px;height:10px" >+i+'" class="progresssc" scid="'+i+'">删除';
i = i+1;
$("#zhanshi").append(html);
})
});
$("#zhanshi").on("click",".progresssc",function () {
//删除准备上传的文件
var id = $(this).attr("scid")
data.delete("myfile_"+id);
$(this).parent("div").remove();
});
function shangchuan(key,value)
{
//截图key后面的数字
var index = key.split("_").pop();
var ext = value.name.split(".").pop();
console.log(key+"来了");
//console.log(value);
if(ext !== "txt") {
$("#hezi_"+index).append("上传失败:上传的文件类型不正确");
return key;
}
if(value.type !== "text/plain") {
$("#hezi_"+index).append("上传失败:上传的文件类型不正确");
return key;
}
if ((value.size/1024)>(10*1024)) {
$("#hezi_"+index).append("上传失败:上传的文件大小为10M");
return key;
}
var formData = new FormData();
formData.append("wenjian",value)
$.ajax({
url: 'sc.php',
type: 'POST',
data: formData,
cache: false,
processData: false,
contentType: false,
dataType:'json',
xhr: function () {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function (e) {
//外部资源加载过程中触发,默认500毫秒。
//loaded代表上传了多少
//total代表总数为多少
var progressRate = Math.round((e.loaded / e.total) * 100,-2) + '%';
//console.log(progressRate);
//通过设置进度条的宽度达到效果
$("#percent_"+index).html(progressRate)
$("#progressnumber_"+index).css("width",progressRate);
})
xhr.upload.addEventListener('load', function (e) {
//外部资源加载成功时触发。如果后台处理时间过长,可以在此提示“后台正在处理请稍等”
})
return xhr;
},
success: function (res) {
if(res.status=='fail') {
console.log("失败了");
$("#hezi_"+index).append("上传失败:"+ res.msg +"");
}else if(res.status=='success'){
$("#shanchu_"+index).remove();
$("#hezi_"+index).children('.shibai_tishi').remove();
console.log(res.data);
//可以把返回的上传路径展示在页面中
}else {
$("#hezi_"+index).append("上传失败:未知原因");
}
return key;
}
});
}
$("#shangchuan").click(function(){
if (!data) {
alert("请上传文件");
return false;
}
var upload_data = data;
//点击上传就清空data数据
data = new FormData();
for (var key of upload_data.keys()) {
if(key && upload_data.get(key)) {
shangchuan(key,upload_data.get(key))
}
}
});
})
</script>
</body>
</html>
<?php
ini_set('display_errors', 0);
error_reporting(E_ALL^E_NOTICE^E_WARNING);
$field = "wenjian";
if(!isset($_FILES[$field])) {
exit(json_encode(['status'=>'fail',"msg"=>"请上传文件","data"=>""]));
}
if ($_FILES[$field]['tmp_name'])
{
$error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];
switch($error)
{
case 1: // UPLOAD_ERR_INI_SIZE
exit(json_encode(['status'=>'fail',"msg"=>"上传的文件超过限制","data"=>""]));
break;
case 2: // UPLOAD_ERR_FORM_SIZE
exit(json_encode(['status'=>'fail',"msg"=>"上传的文件超过表单限制","data"=>""]));
break;
case 3: // UPLOAD_ERR_PARTIAL
exit(json_encode(['status'=>'fail',"msg"=>"对不起,文件上传不完整!","data"=>""]));
break;
case 4: // UPLOAD_ERR_NO_FILE
exit(json_encode(['status'=>'fail',"msg"=>"请选择上传的文件!","data"=>""]));
break;
case 6: // UPLOAD_ERR_NO_TMP_DIR
exit(json_encode(['status'=>'fail',"msg"=>"文件上传没有临时目录!","data"=>""]));
break;
case 7: // UPLOAD_ERR_CANT_WRITE
exit(json_encode(['status'=>'fail',"msg"=>"对不起,文件写入失败!","data"=>""]));
break;
default :
break;
}
$ext = explode('.', $_FILES[$field]['name']);
$ext = end($ext);
$ext = strtolower($ext);
if(!in_array($ext,array('txt')))
{
exit(json_encode(['status'=>'fail',"msg"=>"后缀不正确","data"=>""]));
}
$file_size = round($_FILES[$field]['size']/1024,2); //单位kb
if($file_size>10240)
{
//10M
exit(json_encode(['status'=>'fail',"msg"=>"文件大小请限制在10M以内","data"=>""]));
}
$upload_path = "./upload/";
$file_name = uniqid().rand(1,99999).time().'.'.$ext;
//开始上传我们将尝试使用副本()。如果该操作失败 我们将使用函数()。这两个应该之一 在大多数环境中可靠地工作
if ( ! copy($_FILES[$field]['tmp_name'], $upload_path.$file_name))
{
if ( ! move_uploaded_file($_FILES[$field]['tmp_name'], $upload_path.$file_name))
{
exit(json_encode(['status'=>'fail',"msg"=>"上传失败了。","data"=>""]));
}
}
//因为我这里读取txt文件内容,不需要保存文件就直接删除了
//unlink($upload_path.$file_name);
exit(json_encode(['status'=>'success',"msg"=>"成功","data"=>trim($upload_path.$file_name)]));
}
exit(json_encode(['status'=>'fail',"msg"=>"请上传文件","data"=>""]));
?>