(碎碎念: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清空已选择文件并重新选择同名文件

下载源码

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐