done回调中append DOM是最直接的上传成功后展示列表方式,需用服务器返回的真实文件地址插入可操作条目,避免混淆预览逻辑,指定容器须提前存在且每次append前清空,多文件时注意响应数据结构。
上传成功后展示列表,核心动作发生在 done 回调里——它拿到服务器返回的真实文件地址(如 res.data.url 或 res.msg),此时才该往页面插入可点击、可删除的条目。
常见错误是把预览逻辑(before 或 preview)当成“上传成功后展示”,结果用户看到的是本地 base64 图,而非服务器上已存的正式链接,一旦刷新就丢失。
<div id="file-list"></div>,不能靠 done 里动态创建父容器再塞内容$('#file-list').empty(),避免重复提交时列表越积越多done 里别只取 res.data[0],得确认后端返回的是数组还是单对象;多数场景下,Layui 每次只传一个文件,所以 done 会触发多次done: function(res) { if (res.code === 0) { const item = <div class="file-item"> <a href="${res.data.url}" target="_blank">${res.data.name || '下载'}</a> <button class="layui-btn layui-btn-danger layui-btn-xs" data-url="${res.data.url}">删除</button> </div>; $('#file-list').append(item); }}
当需要排序、批量删除、或提交时按顺序传参,光靠直接 append DOM 不够——DOM 顺序和数据顺序容易脱节。推荐用一个全局数组(如 uploadedFiles = [])存每次上传成功的元信息,再集中渲染。
这么做能绕过 DOM 操作的副作用,比如事件绑定错位、重复追加、或移动端 click 失效等问题。
done 里 push 数据:uploadedFiles.push({ name: res.data.name, url: res.data.url, id: res.data.id });
renderFileList() 函数,遍历 uploadedFiles 生成 HTML 字符串,一次性 $('#file-list').html(...)
$(this).closest('.file-item').remove(),而是从数组里 splice 对应项,再重 render——否则数组和视图永远不同步id 是数据库主键,把它存在 data-id 属性里,后续删除接口就能精准传参纯 DOM 插入后,没样式就是一堆裸链接;没事件绑定,点不了也删不掉。这两块不是可选,是必须补上的最小闭环。
#file-list { padding: 5px 0; },每个条目加 display: flex; align-items: center; justify-content: space-between;
$('#file-list').on('click', '.layui-btn-danger', function() { ... })
<img src="${url}" style="max-width:40px;">,但要先判断 /image//.test(url),避免非图 URL 报错.file-item 加 padding: 8px 12px,比只点按钮更友好页面加载后要显示“之前已上传的文件”,这个动作和上传流程无关,是独立的数据回填逻辑。很多人误以为调一次 upload.render() 就能自动回显,其实它只管新上传,不管历史数据。
/api/files?bizId=123),拿到已有文件列表数组renderFileList(files),而不是等 upload 实例触发任何回调upload.render 的配置里——elem 只是触发上传的按钮,不是展示区bindAction(比如“上传”按钮),确保回显完成后再初始化 upload,否则可能干扰初始状态