(碎碎念:layui都关站了,要不是维护旧项目,谁还会想用layui和JQ啊!!!)
Layui版本2.6.8
JQuery版本3.6.0
由于layui的上传功能做的比较简单,若仅仅用来上传单张图片那还是挺方便的,但如果是上传多张图片,那么就会发现很不好操作。本文将展示如何使用layui实现上传多张图片,预览图片,删除选择图片,限制上传数量等功能,希望可以帮助各位同学(文末附源码)。
1. 创建上传按钮,并实例化上传组件
<button type="button" id="uploader-choose">选择文件</button>
<button type="button" id="uploader-submit">点击上传</button>
<!--文件列表-->
<div class="file-list"></div>
<script>
layui.use('upload', function(){
var upload = layui.upload;
// 上传文件队列
var uploadList = {};
// 文件列表dom
var fileListDom = $('.file-list');
//执行实例
var uploadInst = upload.render({
elem: '#uploader-choose', //绑定元素
url: '/index/upload', //上传接口
accept:'images',
acceptMime:'image/*',
exts:'jpg|png|gif|bmp|jpeg',
auto: false,
bindAction: '#uploader-submit',
multiple: true,
number: 10,
// 选择文件的回调
choose: function(obj){ },
// 上传接口请求成功的回调
before: function(obj){ },
//上传完毕回调
done: function(res){ },
//当文件全部被提交后,才触发
allDone: function (obj) { },
//请求异常回调
error: function(){ }
});
});
</script>
效果图
- 我们关闭了自动上传功能(auto:false)所以需要绑定(bindAction)一个按钮来实现提交上传,关闭自动上传可以更方便的控制上传文件数量。
- 由于我们是上传图片,所以配置了accept、acceptMime、exts参数,对格式做了相应的限制,若是其他文件,修改成对应格式即可。
- 开启可选多个文件 (multiple:true),并配置 number:10。这里需要注意!number 参数表示打开选择文件窗口时可选的文件数量,并不是整个文件队列的文件数量,所以整个文件队列的数量是要手动进行控制的。
- 特别提醒一下,若使用了 $(function(){ … }) ,那么在 function() 中的变量,在外部是无法获取的,因为它的作用域只在function()中。如果必须要使用,需要在 function() 传递过去。(后面会有相关例子说明)
2. 增加选择文件的回调事件 choose(),并实现文件预览与删除
var uploadInst = upload.render({
...
choose: function(obj){
// 展示上传按钮
$('#uploader-submit').show();
// 将每次选择的文件追加到文件队列
uploadList = obj.pushFile();
const len = fileListDom.find('.file-list-item').length;
// 还可以上传的文件数量
const limit = 10 - len;
var number = 0;
// 预读本地文件,如果是多文件,则会遍历。(不支持ie8/9)
obj.preview(function(index, file, result){
if (number < limit){
number++;
appendFile(index, file.name, result);
}else{
deleteTempFile(index)
}
})
})
...
})
// 预览选择的文件
function appendFile(index, name, result) {
const dom = '<div class="file-list-item file-temp" data-index="'+index+'"><div><img src="'+result+'" alt="'+name+'"><span class="layui-badge layui-bg-blue">待上传</span></div>' +
'<div><input type="button" class="file-cancel" value="取消"></div></div>';
fileListDom.append(dom);
fileCancelEvent();
}
// 为待上传文件【取消】按钮添加点击事件
function fileCancelEvent() {
fileListDom.find('.file-cancel').each(function () {
const event = $._data($(this)[0],"events");
// 仅对未绑定事件的按钮进行绑定
if (!event || !event["click"]){
$(this).click(function () {
var fileDom = $(this).parent().parent();
var index = fileDom.data('index');
if (index){
deleteTempFile(index);
}
fileDom.remove();
})
}
})
}
// 删除待上传的文件(从文件队列中删除文件)
function deleteTempFile(index){
if (index === 0){
// 清空文件队列中所有数据
for (const key in uploadList) {
delete uploadList[key];
}
// 隐藏上传按钮
$('#uploader-submit').hide();
}else{
delete uploadList[index];
var number = Object.keys(uploadList).length;
// 若上传文件队列中无数据则隐藏上传按钮
if (number <= 0){
$('#uploader-submit').hide();
}
}
}
效果图
- 为了实现预览功能,我们需要在 choose() 回调中生成图片节点,追加到列表中。参数 obj 为本次选择的文件信息。
- 通过 pushFile() 可以得到文件列表对象,每次调用都会把本次选择的文件追加到列表中。
- preview() 会遍历本次选择的文件,其中 result 为图片base64编码,我们可以直接在页面上展示出来。
- 在生成预览图片时,我们并没有直接在按钮上添加onclick,而是选择了获取按钮,再添加。这是因为文件队列对象变量声明在 layui.use(function()) 中,若直接在按钮上添加删除事件,则会出现找不到队列变量的错误。如果需要直接添加删除事件,则可以把队列变量以及删除事件都移动到 function() 外。
3. 文件上传成功的处理
var uploadInst = upload.render({
...
// 上传接口请求成功的回调
before: function(obj){
layer.load(1);
},
//上传完毕回调
done: function(res){
fileListDom.find('.file-temp').each(function () {
if (!res.res){
// 若上传失败,则直接移除
$(this).remove();
}else{
// 添加上传返回的数据到对应的文件中
var hidden = '<input type="hidden" name="path[]" value="'+res.path+'"/>';
$(this).append(hidden);
// 修改预览文件样式
$(this).removeClass('file-temp');
$(this).find('.file-cancel').removeClass('layui-btn-primary');
$(this).find('.file-cancel').addClass('layui-btn-danger');
$(this).find('.file-cancel').val('删除');
$(this).find('.layui-badge').remove();
}
})
},
//当文件全部被提交后,才触发
allDone: function (obj) {
layer.msg("已上传 "+obj.successful+" 个文件");
layer.closeAll('loading');
deleteTempFile(0)
},
...
})
效果图
- 每个文件上传成功后都会触发 done() 事件,此时我们通过添加隐藏域的方式,保存返回的图片数据,然后再提交到后台(一般的上传图片都是在form表单中进行提交)。这里需要根据后端保存文件的方式进行变动,若上传图片后即整个业务流程结束,则无需添加隐藏域,直接修改预览图片样式即可。
- 文件全部上传结束后,需要清空文件队列对象,否则再次上传时,还会附带之前的文件。
4. 补充:对上传组件添加选择图片数量限制
若还需要更人性化一点的话,可以对上传组件进行重载,修改配置中的 number 参数。这里就不再演示了。
const len = fileListDom.find('.file-list-item').length;
uploadInst.reload({
number: 10-len
});
相关参考
图片/文件上传 - layui.upload
layui 文件上传upload.render清空已选择文件并重新选择同名文件