LayUI多文件上传,支持历史上传预览
记录一次项目开发中,LayUI多个图片进行优化,需要支持多个图片上传、可删除某一个图片、支持加载上次上次图片。
页面代码:
<divclass="layui-upload"> <buttontype="button"class="layui-btn layui-btn-normal"id="ID-upload-demo-files">选择多文件</button> <divclass="layui-upload-list"> <tableclass="layui-table"> <colgroup> <colstyle="min-width: 100px;"> <colwidth="100"> <colwidth="150"> <colwidth="260"> <colwidth="100"> </colgroup> <thead> <th>图片</th> <th>文件名</th> <th>大小</th> <th>上传进度</th> <th>操作</th> </thead>@*历史数据*@<tbodyid="ID-upload-pre-files-list">@{
var filelist = ViewData["UploadedList"] as List<MultiPics>;
if (filelist != null && filelist.Count > 0)
{
foreach (var file in filelist)
{<trid="fileList@((filelist.IndexOf(file)+1).ToString())"> <td> <imgsrc="@file.Content"class="tdPreImg"> </td> <td> <iclass="del-img"id="@((filelist.IndexOf(file)+1).ToString())"data-src="@file.FilePath"></i>@file.FileName</td> <td>@file.FileSize KB</td> <td>已上传</td> <td>@*因为layui按钮会提交,此处后台加载的图片,不用layui按钮*@<inputtype="button"value="删除"class="btn_del"id="btn_del@((filelist.IndexOf(file)+1).ToString())"data-index="@((filelist.IndexOf(file)+1).ToString())" /> </td> </tr>}
}
}</tbody>@*当前上传*@<tbodyid="ID-upload-demo-files-list"> </tbody> </table> </div> <buttontype="button"class="layui-btn"id="ID-upload-demo-files-action">开始上传</button> </div>
LayUI js 代码:
layui.use(function() {var upload =layui.upload;var element =layui.element;var $ =layui.$;var deliveryId = $("#LogID").val(); //制作多文件上传表格 var uploadListIns =upload.render({
elem:'#ID-upload-demo-files',
elemList: $('#ID-upload-demo-files-list'), //列表元素对象 url: '/Ship/OrderInfo/UploadImages?id=' +deliveryId,
accept:'images',
multiple:true,
number:10,
exts:"png|jpg|jpeg",
auto:false,
bindAction:'#ID-upload-demo-files-action',
choose:function(obj) {var that = this;//将每次选择的文件追加到文件队列 var files = this.files =obj.pushFile();//读取本地文件 obj.preview(function(index, file, result) {//console.log('choose' + index) var tr = $(['<tr id="upload-' + index + '">','<td>' + '<img src=\'' + result + '\' class=\'tdPreImg\'>' + '</td>','<td>' + '<i class="del-img" id="del-'+index+'" data-src=""></i>' + file.name + '</td>','<td>' + (file.size / 1024).toFixed(1) + 'kb</td>','<td><div class="layui-progress" lay-filter="progress-demo-' + index + '">' + '<div class="layui-progress-bar" lay-percent=""></div></div>' + '</td>','<td>','<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>','<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>','</td>','</tr>'].join(''));//单个重传 tr.find('.demo-reload').on('click', function() {
obj.upload(index, file);
});//删除 tr.find('.demo-delete').on('click', function() {delete files[index]; //删除对应的文件 tr.remove(); //删除表格行 //清空 input file 值,以免删除后出现同名文件不可选 uploadListIns.config.elem.next()[0].value = '';
});
that.elemList.append(tr);
element.render('progress'); //渲染新加的进度条组件 });
},
done:function (res, index, upload) { //成功的回调 //console.log('done' + index) //删除文件队列已经上传成功的文件【很重要防止之前的图片重复上传】 delete this.files[index];var that = this;var tr = that.elemList.find('tr#upload-' +index);var tds =tr.children();if (res.result) { //上传成功 $('#del-' + index).attr('data-src', res.data) //清空操作 tds.eq(3).html('');
tds.eq(3).html('上传成功!');
}else{this.error(index, upload);
tds.eq(3).html('上传失败!');//弹框显示错误信息 layer.msg("上传失败!" +res.msg);//调试人员查看,暂时保留 console.log("上传失败!" + res.msg + "#" +res.data);
}
},
allDone:function (obj) { //多文件上传完毕后的状态回调 console.log(obj);
},
error:function (index, upload) { //错误回调 var that = this.elemList.find('tr#upload-' +index);//console.log(that); that.find(".demo-reload").removeClass('layui-hide');
},
progress:function(n, elem, e, index) {
element.progress('progress-demo-' + index, n + '%'); //执行进度条。n 即为返回的进度百分比 }
});
});
页面加载数据和提交表单js
var main ={
@*初始化,静态js*@
Init:function() {
$(document).ready(function() {
@* Layui自带图片删除,历史图片的删除需特殊处理 *@
$(".btn_del").click(function() {var _index = this.getAttribute("data-index");var _tr = $("#fileList" +_index);
$("#ID-upload-pre-files-list")[0].removeChild(_tr[0]);
})
});
},
@* 获取参数,前台不提交文件,后台绑定 *@
SaveSignBack:function() {
@*图片地址列表*@var _BackImage = "";
@*发货日志*@var _ID = $("#LogID").val();var _Note= $("#Note").val();//图片提取并限制数量 var images_ids = $('.del-img');
@*限制上传图片数量*@if (images_ids.length > 10) {
layer.msg("图片最多选择10张");return false;
}
@*以|竖线分割,拼接字符串*@if(images_ids.length) {var images = '';
$.each(images_ids,function(index, val) {if (images == '') {
images+= $(val).attr('data-src')
}else{
images+= '|' + $(val).attr('data-src')
}
});//$(data.form).append('<input name="images" type="hidden" value="' + images + '">');//插入表单 //图片参数赋值 _BackImage=images;
}
@*获取表单内容序列化*@//var fileForm = $("#form1").serialize(); //上传了图片,直接修改 if(_BackImage.length) {
main.FormSubmit(_LogID, _Note, _BackImage);
}//未上传图片,弹框提示 else{
$.messager.confirm("提示", "您未上传图片,确定提交吗?", function(data) {//确定 if(data) {
main.FormSubmit(_LogID, _Note, _BackImage);return;
}//修改,不处理 else{ }
});
}
},@* 提交后台 *@
FormSubmit:function(_LogID, _Note, _BackImage) {
$.post("/ControllerName/OrderInfo/BackSubmit",
{
LogID: _LogID,
Note: _Note,
Images: _BackImage
},function(obj) {if(obj.result) {
layer.msg(obj.msg);//parent.refresh(); parent.location.reload();
parent.CloseWin();
}else{
$.messager.alert('Info', obj.msg, 'info');
}
}
);
},
}
$(function() {
main.Init();
})
后台C#上传代码,表单提交后台代码就不贴了
public ActionResult UploadImages(int ID = 0)
{////防止异常加载图片覆盖,延时半秒 SaveAs //System.Threading.Thread.Sleep(500); try{#region 数据校验 //登录状态校验 if (CurrentUser.Id == 0)
{return Json(new { result = false, msg = "登录失效!", data = ""});
}//获取回签单图片列表 HttpFileCollectionBase files =HttpContext.Request.Files;//图片非空校验 if (files.Count == 0)
{return Json(new { result = false, msg = "上传失败!请上传回签单图片!", data = ""});
}//单个图片轮询上传,只能单张上传 if (files.Count > 1)
{ return Json(new { result = false, msg = "参数错误!", data = ""});
}#endregion //上传文件计数 var successCount = 0;//图片相对路径(用于数据库保存) string FilePath = string.Empty;//循环保存图片,实际单个图片上传 for (int i = 0; i < files.Count; i++)
{#region 拼接文件名(不含路径) //文件类型 var fileType = string.Empty;//获取文件类型 if (files[i].ContentType == "image/jpeg" || files[i].ContentType == "image/jpg")
{
fileType= ".jpg";
}else if (files[i].ContentType == "image/png")
{
fileType= ".png";
}//生成随机4位数字 var rand = (new Random()).Next(1000, 10000).ToString();//文件名 var _name = ID + "_" + CurrentUser.Id + "_" + DateTime.Now.ToString("yyMMddHHmmsss") + "_" +rand;//拼接文件名 回签图片名称格式:发货日志Id_上传人_年月日_4位随机数 var book = _name +fileType;#endregion //获取配置文件的回签单保存路径 SignBackUrl string savePath = System.Configuration.ConfigurationManager.AppSettings["FileUrl"];//按月分文件夹 FilePath = DateTime.Now.ToString("yyyyMM") + "/" +book;//文件完整路径 string fileFullPath = savePath + "/" +FilePath;//没有文件夹则创建 if (!Directory.Exists(savePath + "/" + DateTime.Now.ToString("yyyyMM")))
{
Directory.CreateDirectory(savePath+ "/" + DateTime.Now.ToString("yyyyMM"));
} #region 文件大小校验 //保存图片到服务器上 files[i].SaveAs(fileFullPath);//创建文件 获取文件大小 var fileInfo = newFileInfo(fileFullPath);//获取文件大小,单位KB 1KB=1024byte(字节) decimal fileSize = (decimal)(fileInfo.Length > 0 ? (fileInfo.Length / 1024) : 0);//2MB转成KB var _2mb = (decimal)2 * 1024;//获取大小异常 if (fileSize == 0)
{//计算文件大小异常 return Json(new { result = false, msg = "计算文件大小异常 !", data =FilePath });
}else if (fileSize != 0 && fileSize >_2mb)
{//文件大小超出2MB return Json(new { result = false, msg = "文件大小超出2MB,请修改后重试 !", data =FilePath });
}#endregion//累计成功计数 successCount++;
}if (successCount ==files.Count)
{//成功返回,回调图片地址列表(相对地址) return Json(new { result = true, msg = "上传成功 !", data =FilePath }); }else{//失败 return Json(new { result = false, msg = "上传失败 !", data = "[上传文件数:" + successCount + "]"});
}
}catch(Exception ex)
{//抛出异常 return Json(new { result = false, msg = "上传异常,请重试 !", data = "[Exception:" + ex.Message + "]"});
}
}
上传图片时,出现上传图片名称和图片不能对应,数据串了问题。但是能想到可能是前一张图片没有保存,后面一张图片已经执行到保存方法,导致覆盖了。尝试了增加延时、后台记录id等一系列操作后,才发现是生成图片名称只到天。
后加了到秒并加了四位随机数,才得以解决。
Layui实际上是每上传一次图片,调用一次后台上传方法。
这里表格id " ID-upload-demo-files-list"是layui指定表格Id。已经上传的历史数据,不能用这个Id显示,单独加了一个tbody id="ID-upload-pre-files-list"用于显示已上传图片。需要删除,找到这行Dom移除即可。
提交表单