layui多文件列表上传+上传中loading效果

layui文件上传实践
本文介绍了一个基于layui框架的文件上传功能实现案例,该案例适用于公告发布等模块中的文件上传需求,详细展示了如何进行多文件上传、上传过程中的状态更新及上传后文件列表的管理。

描述

项目中实际使用的例子,不是单一个上传。

是添加公告、添加帖子等等模块中的一个功能。

从layui官网的例子做一些改动,没有进度条(太难了),而是在每一行加了loading效果。

此功能是选择文件后直接上传。

如果用的官网例子,选择文件先不上传的那种,改一下不难。

功能描述

点击选择文件按钮,选择文件后在表格追加一行,直接上传

上传中:

上传成功:

删除的是文件的id,入表时的关联字段,不需要可删除(官网例子中删除的是上传列表中的数据)

上传失败:

这里没图,就是状态为:上传失败,没有操作按钮(官网例子中有重传按钮功能)

 

 实施

attachmentId:字符串。如公告表中的字段attachmentId,表示关联的文件id(id+逗号)[1001,1002,1003,1004,]

html

<input>是用来放已上传文件的id(形如:attachmentId="id1,id2,id3,"),用来入表的。

<input type="text" id="attachmentId" style="display: none">
<div class="layui-form-item">
    <div class="layui-upload">

        <div class="layui-upload-list">
            <table class="layui-table">
                <thead>
                <tr><th>文件名</th>
                    <th>大小</th>
                    <th>状态</th>
                    <th>操作</th>
                </tr></thead>
                <tbody id="demoList"></tbody>
            </table>
        </div>
        <button type="button" class="layui-btn layui-btn-normal" id="testList">选择文件</button>
    </div>
</div>

 js

layui.use(['upload'], function(){
        var upload = layui.upload;
        //多文件列表上传
        var attachmentId = "";//上传的文件id串
        var demoListView = $('#demoList')
            ,uploadListIns = upload.render({
            elem: '#testList'
            ,url: ...
            ,accept: 'file'
            ,multiple: true
            ,auto: true
            ,before: function(obj){
                
            }
            ,choose: function(obj){
                var files = this.files = obj.pushFile(); //将每次选择的文件追加到文件队列
                //读取本地文件
                obj.preview(function(index, file, result){
                    var tr = $(['<tr id="upload-'+ index +'">'
                        ,'<td>'+ file.name +'</td>'
                        ,'<td>'+ (file.size/1014).toFixed(1) +'kb</td>'
                        ,'<td><i class="layui-icon layui-icon layui-anim layui-anim-rotate layui-anim-loop">&#xe63d;</i></td>'
                        ,'<td>'
                        ,'<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete layui-hide">删除</button>'
                        ,'<input class="layui-hide" type="text" id='+index+'>'
                        ,'</td>'
                        ,'</tr>'].join(''));

                    //删除
                    tr.find('.demo-delete').on('click', function(){
                        var tem = $("#"+index).val();
                        attachmentId = attachmentId.replace(tem,"");
                        $("#attachmentId").val(attachmentId);
                        delete files[index];
                        tr.remove();
                        uploadListIns.config.elem.next()[0].value = ''; //清空 input file 值,以免删除后出现同名文件不可选
                    });

                    demoListView.append(tr);
                    delete files[index];
                });

            }
            ,done: function(res, index, upload){
                var data = res;
                var attachmentId_tem = data.fileName + ",";
                $("#"+index).val(attachmentId_tem);
                attachmentId += (attachmentId_tem);
                $("#attachmentId").val(attachmentId);
                if("这里可以加上自己的判断"){ //上传成功
                    var tr = demoListView.find('tr#upload-'+ index)
                        ,tds = tr.children();
                    tds.eq(2).html('<span style="color: #5FB878;">上传成功</span>');
                    tds.eq(3).find('.demo-delete').removeClass('layui-hide'); //显示删除
                    return delete this.files[index]; //删除文件队列已经上传成功的文件
                }
                this.error(index, upload);
            }
            ,error: function(index, upload){
                var tr = demoListView.find('tr#upload-'+ index)
                    ,tds = tr.children();
                tds.eq(2).html('<span style="color: #FF5722;">上传失败</span>');
                return delete this.files[index];
            }

        });


    })

修改

在修改功能中,需要回显已上传列表,并且可以删除已上传文件。

把上面代码中的的id改一下就行,其他基本不用改,或者想办法复用上面的代码也可以,我自己没复用。

用attachmentId查出已上传的文件(或者说已关联的文件),下面是ajax请求中success中的处理。

success: function (res) {
    var data = res.list;
    for (var i=0;i<data.length;i++) {
        var tr = $(['<tr id="upload-'+ i +'">'
            ,'<td>'+ data[i].uploadFileName +'</td>'
            ,'<td>'+ data[i].fileSize +'kb</td>'
            ,'<td><span style="color: #5FB878;">已上传</span></td>'
            ,'<td>'
            ,'<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete2">删除</button>'
            ,'<input class="layui-hide attId" value="'+data[i].id+'," type="text">'
            ,'</td>'
            ,'</tr>'].join(''));
        $('#demoList2').append(tr);

    }
    // 已有文件删除
    $('.demo-delete2').on('click', function(){
        var attachmentId2 = $("#attachmentId2").val();
        var tem = $(this).parents("tr").find(".attId").val();
        attachmentId2 = attachmentId2.replace(tem,"");
        $("#attachmentId2").val(attachmentId2);
        $(this).parents("tr").remove();
    });
}

 

结语

还有一些小的页面bug,自己多测一下(比如打开弹出层时先清空文件表格的html,否则上传之后关闭弹框再打开会出现上次的内容)

整个功能都围绕attachmentId,一定注意。

还有就是和进度条的集成,查出来的都是改源码那一套,试了好久没什么用,而且也不是实时进度,有好的方法可以交流。

<think>由于问题涉及前端(layui、AJAX)、后端(纯ASP)和文件上传,我将分步骤解释。 1. 前端部分:使用layui多文件上传组件,并通过AJAX发送FormData。 2. 后端部分:使用纯ASP(VBScript)处理上传的文件。 注意:纯ASP处理文件上传比较复杂,因为ASP本身没有内置的文件上传组件,我们需要使用第三方组件或者自己解析请求二进制流。但问题要求无组件,因此我们必须自己解析上传的数据流。 由于自己解析二进制流较为复杂,这里我将提供一个简化的方法,但请注意,对于生产环境,建议使用成熟的第三方组件(如Persits.Upload)以避免安全漏洞和复杂的处理逻辑。但题目要求无组件,所以我们将自己解析。 然而,由于ASP的局限性,无组件上传处理代码较为冗长,且对于大文件支持可能不够好。 我们将分为两部分: - 前端:layui多文件上传,使用AJAX发送FormData - 后端:ASP解析多文件上传 首先,前端部分: 使用layuiupload模块,注意layuiupload模块默认是多文件上传,我们通过设置`multiple: true`(实际上layui默认就是多文件)。我们使用AJAX发送FormData。 但是注意:layuiupload模块在上传时默认就是使用FormData,所以我们只需要配置好参数即可。 前端示例代码: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>layui多文件上传</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css"> </head> <body> <div class="layui-upload"> <button type="button" class="layui-btn layui-btn-normal" id="chooseFile">选择多文件</button> <button type="button" class="layui-btn" id="uploadBtn">开始上传</button> </div> <script src="https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/layui.js"></script> <script> layui.use('upload', function() { var $ = layui.jquery; var upload = layui.upload; // 多文件列表示例 var demoListView = $('#demoList'); // 初始化上传控件 upload.render({ elem: '#chooseFile' ,url: '/upload.asp' // 你的ASP上传接口 ,accept: 'file' ,multiple: true ,auto: false // 关闭自动上传,由按钮触发上传 ,bindAction: '#uploadBtn' // 绑定上传按钮 ,choose: function(obj) { // 将每次选择的文件追加到文件队列 var files = this.files = obj.pushFile(); // 当前选中的文件 // 预读本地文件示例,不支持ie8 obj.preview(function(index, file, result){ // 这里可以显示选中的文件信息 console.log(file.name); }); } ,before: function(obj) { // 这里可以显示加载动画 layer.msg('上传中', {icon: 16, shade: 0.01, time: 0}); } ,done: function(res){ layer.closeAll('loading'); // 关闭加载动画 // 上传完毕 if (res.code == 0) { layer.msg('上传成功'); } else { layer.msg('上传失败'); } } ,error: function(index, upload){ // 请求异常回调 layer.msg('上传失败'); } }); }); </script> </body> </html> ``` 注意:上面的代码中,我们使用了layuiupload模块,设置了`auto:false`,然后通过另一个按钮`#uploadBtn`来触发上传。在`choose`回调中,我们可以预览文件,但这里只是简单打印文件名。 接下来,重点在后端:纯ASP处理多文件上传。 由于ASP没有内置的文件上传处理功能,我们需要自己解析Request.BinaryRead读取的二进制流。这里我们将使用一段经典的VBScript代码来解析多文件上传。注意,这个解析器可能不能处理所有情况,但对于一般情况是有效的。 以下是upload.asp的代码: ```asp <% Option Explicit ' 设置脚本超时为10分钟(600秒),以便上传大文件 Server.ScriptTimeout = 600 ' 定义变量 Dim binData, intDataByteCount, strData, strBoundary, lngBoundaryPos, lngStart, lngEnd, lngFileStart, lngFileSize Dim strContentDisposition, strFileName, strContentType, strFieldName, strValue, strUploadedFiles Dim objStream, binFileData, fs, outputFile, outputPath, savePath, filePath Dim lngCurrentPos, lngDataEnd, lngPos, lngFileNameStart, lngFileNameEnd ' 获取二进制数据 intDataByteCount = Request.TotalBytes binData = Request.BinaryRead(intDataByteCount) ' 查找边界字符串 strData = BinaryToString(binData) strBoundary = Mid(strData, 1, InStr(1, strData, vbCrLf) - 1) ' 初始化 lngStart = Len(strBoundary) + 3 lngBoundaryPos = InStr(lngStart, strData, strBoundary) ' 设置上传路径 (注意:需要修改为服务器上的实际路径,并且要有写入权限) savePath = "D:\upload\" ' 例如:D:\upload\,请确保此目录存在且有写入权限 ' 如果不存在该目录,则创建(需要FileSystemObject支持) Set fs = Server.CreateObject("Scripting.FileSystemObject") If Not fs.FolderExists(savePath) Then fs.CreateFolder(savePath) End If ' 循环处理每个部分 Do While lngBoundaryPos > 0 lngEnd = lngBoundaryPos - 1 lngFileStart = InStr(lngStart, strData, "filename=""") If lngFileStart > 0 And lngFileStart < lngEnd Then ' 处理文件字段 lngFileNameStart = lngFileStart + 10 lngFileNameEnd = InStr(lngFileNameStart, strData, """") strFileName = Mid(strData, lngFileNameStart, lngFileNameEnd - lngFileNameStart) strFileName = Mid(strFileName, InStrRev(strFileName, "\") + 1) ' 去掉路径,只取文件名 ' 获取Content-Type lngStart = InStr(lngFileNameEnd, strData, "Content-Type: ") + 14 lngEnd = InStr(lngStart, strData, vbCrLf) strContentType = Mid(strData, lngStart, lngEnd - lngStart) ' 找到文件数据的起始位置(两个换行之后) lngStart = InStr(lngEnd, strData, vbCrLf & vbCrLf) + 4 lngEnd = InStr(lngStart, strData, vbCrLf & "--" & strBoundary) If lngEnd = 0 Then lngEnd = lngStart + Len(strData) - lngStart ' 获取文件数据(二进制) Set objStream = Server.CreateObject("ADODB.Stream") objStream.Type = 1 ' adTypeBinary objStream.Open binData.Position = lngStart - 1 binFileData = binData.Read(lngEnd - lngStart) objStream.Write binFileData objStream.Position = 0 ' 保存文件 filePath = savePath & strFileName ' 如果文件已存在,则删除 If fs.FileExists(filePath) Then fs.DeleteFile filePath End If objStream.SaveToFile filePath, 2 ' adSaveCreateOverWrite objStream.Close Set objStream = Nothing ' 记录上传的文件名 strUploadedFiles = strUploadedFiles & strFileName & ", " Else ' 这里可以处理非文件字段(表单字段) ' 但本次问题只关注文件上传,所以省略 End If ' 查找下一个边界 lngStart = lngBoundaryPos + Len(strBoundary) + 2 lngBoundaryPos = InStr(lngStart, strData, strBoundary) Loop ' 释放对象 Set fs = Nothing ' 返回结果(JSON格式) Response.ContentType = "application/json" If strUploadedFiles <> "" Then strUploadedFiles = Left(strUploadedFiles, Len(strUploadedFiles)-2) ' 去掉最后的逗号和空格 Response.Write "{""code"": 0, ""msg"": ""文件上传成功"", ""files"": [""" & strUploadedFiles & """]}" Else Response.Write "{""code"": -1, ""msg"": ""没有文件被上传""}" End If ' 二进制数据转字符串函数 Function BinaryToString(binData) Dim objStream Set objStream = Server.CreateObject("ADODB.Stream") objStream.Type = 1 ' adTypeBinary objStream.Open objStream.Write binData objStream.Position = 0 objStream.Type = 2 ' adTypeText objStream.Charset = "iso-8859-1" ' 注意:这里使用iso-8859-1编码,因为二进制数据直接转为字符串 BinaryToString = objStream.ReadText objStream.Close Set objStream = Nothing End Function %> ``` 重要注意事项: 1. 上述ASP代码中,保存路径`savePath`需要根据实际情况修改,并且要确保该目录存在且有写入权限。 2. 由于无组件上传解析较为复杂,上述代码可能无法处理所有情况(特别是非常大的文件或特殊字符),建议在实际使用中进行充分测试。 3. 该解析代码是基于字符串搜索的,效率可能不高,对于大文件上传可能会消耗较多内存和CPU。 4. 返回的JSON中,上传的文件名列表用逗号分隔,并且被包裹在一个字符串数组里(这里为了简单,实际返回的是一个字符串,而不是真正的数组,你可以根据需要调整)。 由于上述ASP代码较长,且无组件上传处理在ASP中较为繁琐,请确保在安全要求不高的环境中使用,并且对上传文件的大小进行限制(可通过IIS设置或代码中判断文件大小)。 另外,由于ASP的内存限制,上传大文件时可能会出现问题。如果上传文件较大,建议使用分块上传或者改用其他技术栈(如ASP.NET)。 相关问题: §§相关问题§§: 1. 如何在ASP中限制上传文件的大小? 2. 如何优化上述ASP文件上传代码以提高性能和减少内存占用? 3. layui上传模块如何实现上传前的文件类型和大小检查? 4. 在纯ASP环境中,除了自己解析二进制数据,还有哪些方法可以实现文件上传? </think>### 解决方案:LayUI多文件上传 + AJAX + FormData + 纯ASP后端 #### 前端实现(LayUI + AJAX) ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css"> </head> <body> <div class="layui-upload"> <button type="button" class="layui-btn" id="uploadBtn"> <i class="layui-icon"></i>选择多文件 </button> <div class="layui-upload-list" id="fileList"></div> </div> <script src="https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/layui.js"></script> <script> layui.use('upload', function(){ const upload = layui.upload; const $ = layui.$; upload.render({ elem: '#uploadBtn', url: 'upload.asp', // ASP处理接口 multiple: true, // 开启多文件上传 accept: 'file', // 允许所有文件类型 auto: false, // 关闭自动上传 bindAction: '', // 手动触发上传 choose: function(obj){ // 预览文件列表 const files = obj.pushFile(); const html = []; layui.each(files, function(index, file){ html.push('<div id="file-'+ index +'">' + file.name + '<button class="layui-btn layui-btn-xs demo-delete">删除</button>' + '<span class="layui-btn layui-btn-xs upload-btn">上传</span></div>'); }); $('#fileList').html(html.join('')); // 单个文件上传按钮事件 $('.upload-btn').on('click', function(){ const index = $(this).parent().attr('id').split('-')[1]; const file = files[index]; const formData = new FormData(); formData.append('file', file); // 添加文件到FormData // 发送AJAX请求 $.ajax({ url: 'upload.asp', type: 'POST', data: formData, contentType: false, // 必须 processData: false, // 必须 beforeSend: function(){ layer.msg('上传中...', {icon: 16, shade: 0.01}); }, success: function(res){ if(res.code === 0){ layer.msg('上传成功'); $(`#file-${index}`).remove(); } else { layer.msg('失败: ' + res.msg); } }, error: function(){ layer.msg('请求失败'); } }); }); } }); }); </script> </body> </html> ``` #### 后端实现(纯ASP处理) ```asp <%@ Language=VBScript %> <% ' 设置脚本超时时间(秒) Server.ScriptTimeout = 300 ' 创建文件系统对象 Set fs = Server.CreateObject("Scripting.FileSystemObject") ' 获取上传的二进制数据 Dim binData binData = Request.BinaryRead(Request.TotalBytes) ' 设置保存路径(需改为实际物理路径) Dim savePath savePath = "D:\upload\" ' 确保目录存在且有写入权限 ' 文件边界标记 Dim boundary, boundaryPos boundary = MidB(binData, 1, InStrB(1, binData, vbCrLf) - 1) ' 查找文件名 Dim fileNamePos, fileName fileNamePos = InStrB(1, binData, "filename=""", 1) + 10 If fileNamePos > 10 Then fileName = GetFileName(binData, fileNamePos) End If ' 获取文件内容起始位置 Dim fileStart, fileEnd fileStart = InStrB(fileNamePos, binData, vbCrLf & vbCrLf) + 4 fileEnd = InStrB(fileStart, binData, boundary) - 2 ' 提取文件二进制数据 Dim fileData fileData = MidB(binData, fileStart, fileEnd - fileStart) ' 保存文件 If fileName <> "" Then Dim filePath filePath = savePath & fileName ' 创建二进制流 Set stream = Server.CreateObject("ADODB.Stream") stream.Type = 1 ' adTypeBinary stream.Open stream.Write fileData stream.SaveToFile filePath, 2 ' 2=覆盖已存在文件 stream.Close Set stream = Nothing ' 返回JSON响应 Response.ContentType = "application/json" Response.Write "{""code"":0, ""msg"":""上传成功"", ""filename"":""" & fileName & """}" Else Response.Write "{""code"":1, ""msg"":""未检测到文件""}" End If ' 清理资源 Set fs = Nothing ' 辅助函数:从二进制数据提取文件名 Function GetFileName(binData, startPos) Dim endPos, fileNameBytes, i, char endPos = InStrB(startPos, binData, """") fileNameBytes = MidB(binData, startPos, endPos - startPos) For i = 1 To LenB(fileNameBytes) char = AscB(MidB(fileNameBytes, i, 1)) If char > 127 Then GetFileName = GetFileName & "%" & Hex(char) Else GetFileName = GetFileName & Chr(char) End If Next End Function %> ``` ### 代码解释 #### 前端部分 1. **LayUI初始化**: - 使用`upload.render`初始化上传组件 - `multiple: true`启用多文件选择 - `auto: false`关闭自动上传(实现手动触发) 2. **文件选择处理**: - `choose`回调中生成文件列表和操作按钮 - 每个文件生成独立DIV包含删除和上传按钮 3. **AJAX上传**: - 使用`FormData`封装文件数据 - `contentType: false`和`processData: false`确保正确传输二进制数据 - 单个文件独立上传(避免大文件同时上传) #### 后端部分 1. **二进制处理**: - `Request.BinaryRead`获取原始二进制数据 - 通过边界标记定位文件内容 2. **文件提取**: - 从头部信息提取文件名 - 定位文件内容的起始/结束位置 - `MidB`截取文件二进制数据 3. **文件保存**: - 使用`ADODB.Stream`处理二进制流 - `SaveToFile`方法写入磁盘 - 返回JSON格式的响应 ### 关键注意事项 1. **路径权限**: - 确保ASP有写入`D:\upload\`目录的权限 - 生产环境建议使用相对路径 2. **大文件限制**: - 修改IIS的`maxRequestLength`(默认4MB) - 在ASP中设置`Server.ScriptTimeout`避免超时 3. **安全防护**: - 添加文件类型验证(ASP端) - 重命名随机文件名避免覆盖 - 设置磁盘配额限制 4. **编码问题**: - 中文文件名需特殊处理(示例已包含编码转换)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值