Layui表格操作列下载需监听table.on('tool(filter)')事件,严格匹配filter和lay-event值,通过obj.data获取下载URL,用fetch/XmlHttpRequest发带认证请求并处理blob响应,配合模板条件渲染按钮、防重复点击及大文件直链优化。
点击操作列按钮触发下载,必须用 table.on('tool(filter)') 监听
layui 表格的「操作列」按钮(比如带 lay-event="download" 的按钮)本身不带任何行为,点击后只是抛出一个事件,必须手动监听并执行下载逻辑。漏掉这步监听,按钮就完全没反应。
常见错误是只写了模板、渲染了表格,但没写 table.on('tool(...) 回调,结果按钮看起来能点,实际什么也不发生。
- 确保表格配置中的
filter值(如test)和监听时写的字符串完全一致,大小写敏感 -
obj.event必须严格匹配按钮上写的lay-event值,比如lay-event="download"→ 判断if (obj.event === 'download') - 不要在回调里用
obj.tr.find('td').text()取链接——容易取错或含 HTML 标签;应直接用obj.data.downloadUrl这类字段
下载链接来自后端接口,不能直接用 window.location.href 走 GET
如果文件需要权限校验、动态生成、或走 POST 请求(比如带 token 或 body 参数),就不能简单赋值给 window.location.href——这会丢失请求头、body 和 session 上下文,大概率 401 或 404。
正确做法是用 XMLHttpRequest 或 fetch 发起带认证信息的请求,接收 responseType: 'blob',再构造 a 标签触发下载。
- 后端响应头必须包含
Content-Disposition: attachment; filename="xxx.xlsx",否则浏览器可能打开而非下载 -
XMLHttpRequest要显式设responseType = 'blob',否则response是字符串,无法构造有效文件 - 用
URL.createObjectURL(blob)创建临时地址,避免跨域或路径问题;用完记得URL.revokeObjectURL
操作列模板里要控制按钮显隐,别让不可下载的行也显示按钮
直接在模板里硬写 <button lay-event="download">下载</button> 很危险:哪怕某行数据没有 downloadUrl 或状态为禁用,按钮依然存在,用户一点就报错或空白响应。
Layui 模板支持简单条件判断,应该利用 d(即当前行数据)做前置过滤。
<script type="text/html" id="barDemo">
{{# if(d.downloadUrl && d.status === 'done'){ }}
<button class="layui-btn layui-btn-xs" lay-event="download">下载</button>
{{# } else { }}
<span class="layui-badge-rim">不可下载</span>
{{# } }}
</script>- 避免只判
d.downloadUrl,还要结合业务字段如status、isDownloadable等,防止后端返回空 URL - 模板里不要写 JS 逻辑(比如
onclick="downloadFile(...)">),破坏 layui 事件统一管理机制 - 如果需异步判断是否可下载(比如查权限接口),得先禁用按钮、加 loading,再请求后再决定显隐——这时模板不够用,得用
cell事件 + 手动渲染
大文件下载要防重复点击,且注意 Blob 内存占用
用户手快连点两次下载按钮,可能触发两个并发请求,后端重复生成文件、前端创建两个 blob URL,既浪费资源又可能导致文件名冲突或内存泄漏。
简单加锁就能解决,且对用户体验影响极小。
- 在
table.on('tool(...)'回调开头加个标记变量,比如if (downloading) return; downloading = true;,下载完成或失败后重置 - 每次
createObjectURL后,务必在a.click()完成后调用URL.revokeObjectURL(href),尤其在循环下载多文件时 - 超过 100MB 的文件,前端 Blob 下载易卡死或 OOM,应改用后端直链(带时效 token)+
window.open,避开内存中转


















