版权声明:本文为博主原创文章,转载注明地址:http://blog.csdn.net/wang704987562 https://blog.csdn.net/wang704987562/article/details/81810061
功能
1.上传多张图片,放弃传统input.file形式上传,自定义数组保存文件;
2.可一次性选择多张图片,可追加图片,图片可以预览;
3.可拖动图片,顺序默认从左0开始,采用jquery-ui实现;
4.可删除单个图片,或清空所有图片;
5.跨域上传;
6.防止按钮重复提交;
7.判断文件类型,过滤非图片文件;
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>上传多张图片文件,可拖动图片排序</title>
<!--pomelo-toast-->
<link rel="stylesheet" href="http://d3.itsaoko.com/template/source/1880821582xN.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" >
<style>
.container {
width: 705px;
margin: 0 auto;
}
.img_wrapper {
width: 100%;
min-height: 300px;
display: flex;
flex-wrap: wrap;
}
.dragWrapper {
position: relative;
display: inline-block;
}
.btn_wrapper {
display: flex;
justify-content: center;
}
.btn,.clearBtn {
margin-right: 50px;
}
</style>
</head>
<body>
<div class="container">
<div class="img_wrapper">
</div>
<div class="btn_wrapper">
<!--不使用file的默认样式,隐藏file选择框,使用button的click事件触发选择文件-->
<input type="file" name="files" id="files" multiple style="display: none;" data-name="files1"/>
<button class="btn">选择文件</button>
<button class="clearBtn">清空文件</button>
<button class="uploadBtn">上传文件</button>
</div>
</div>
</body>
<!--pomelo-toast-->
<script src="http://d3.itsaoko.com/template/source/18808220295.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script
src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"
integrity="sha256-T0Vest3yCU7pafRw9r+settMBX6JkKN06dqBnpQ8d30="
crossorigin="anonymous"></script>
</html>
JS
<script type="text/javascript">
var toast;
$(document).ready(function() {
toast = new PomeloToast();
//选择文件点击事件
$(".btn").click(function(e){
e.preventDefault();
$("#files").trigger("click");
});
//保存文件数组
var imgFiles = [];
//记录当前文件数
var fileCount = 0;
//文件变化事件
$("#files").change(function() {
var files = $(this)[0].files;
var imageType = /^image\//;
var namePrefix = $(this).data("name");
for(var i = 0;i < files.length;i ++) {
var file = files[i];
var fileType = file.type;
if(!imageType.test(fileType)) {
toast.show("请选择图片类型文件");
return;
}
var fileName = file.name;
//文件的唯一标识
fileCount++;
var fileId = namePrefix + '_' + fileName + '_' + fileCount;
//保存文件到数组
imgFiles.push({
id : fileId,
file : file
});
//预览图片
var render = new FileReader();
render.fileId = fileId;
render.img = $(this);
render.onload = function (e) {
//创建img
var imgHtml = '<div class="dragWrapper" style="">' +
'<img src="' + e.target.result + '" width="100" height="100" data-name="' + e.target.fileId + '" />' +
'<button class="btn default removeImg" style="position: absolute;top: 0;right: 0;margin: 0px;">删除</button>' + '</div>';
e.target.img.parent().siblings(".img_wrapper").append(imgHtml);
};
render.readAsDataURL(files[i]);
}
//清空file框文件,可以连续选择同一文件
$(this).val('');
//刷新拖动排序
$(".container").sortable('refresh');
});
//删除单个文件,因为动态添加,所以使用代理
$(".img_wrapper").on("click", ".removeImg", function() {
var id = $(this).siblings("img").data("name");
var index = 0;
//删除文件
while(index < imgFiles.length) {
if(imgFiles[index].id == id) {
imgFiles.splice(index, 1);
break;
}
index++;
}
$(this).parent().remove();
});
//清空文件
$(".clearBtn").click(function() {
//清空文件数组
imgFiles = [];
$(".img_wrapper").html('');
});
//图片拖动排序
$(".container").sortable({
items:'.dragWrapper'
});
var uploadFinish = true;
//上传文件
$(".uploadBtn").click(function() {
if(imgFiles.length < 1) {
toast.show("文件为空");
return;
}
if(!uploadFinish) {
//文件正在上传
return;
}
uploadFinish = false;
var formData = new FormData();
//设置文件顺序
$.each($("div.img_wrapper"), function(index, value) {
var imgs = $(this).find("img");
var imgOrder = 1;
$.each(imgs, function() {
$(this).attr("data-order", imgOrder);
imgOrder++;
});
});
//设置文件参数 key:name+order value:file
$.each(imgFiles, function(index, value) {
var id = value.id;
//获取该图片对应的顺序
var order = $("img[data-name='" + id + "']").data("order");
id = id.substr(0, id.lastIndexOf("_"));
id = id + "_" + order;
formData.append(id, value.file);
});
$.ajax({
url: 'http://localhost:8080/test/uploads',
data: formData,
type: 'POST',
cache: false,
contentType: false,
processData: false,
success: function(data){
toast.show("上传成功");
//清空文件数组
imgFiles = [];
//清空预览图片
$(".img_wrapper").html('');
},
error: function(e) {
toast.show("上传失败");
},
complete: function() {
//设置请求完成
uploadFinish = true;
}
});
});
});
</script>
后端使用Spring MVC接收文件
TestController
/**
* @author wzx
* @time 2018/8/4
*/
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/uploads")
@ResponseBody
@CrossOrigin(origins = "*", methods = {RequestMethod.POST, RequestMethod.OPTIONS},
allowedHeaders = {"Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"},
exposedHeaders = {"Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"})
public String upload(MultipartFile[] files, HttpServletRequest request) {
System.out.println(files.length);
Map<String, MultipartFile> fileMap = ((DefaultMultipartHttpServletRequest) request).getFileMap();
System.out.println("fileMap size:" + fileMap.size());
fileMap.forEach((k,v)-> System.out.println(k));
return "ok";
}
}
两点说明:
1.可以使用MultipartFile[]数组接收,缺点是files只能跟前端的参数名对应;使用DefaultMultipartHttpServletRequest.getFileMap()获取参数名和对应文件,这里可以处理文件的顺序;
2.@CrossOrigin注解处理跨域请求;