如何在Shiny应用中为JS导出功能添加加载器
给Shiny应用的JS导出PDF功能添加加载器
以下是针对需求修改后的完整代码,通过纯前端JS实现加载器的显示与隐藏,适配原有导出逻辑:
library(shiny) library(shinyWidgets) js <- " function Export(){ // 显示加载器并禁用按钮 $('#loader').show(); $('#export').prop('disabled', true); var $img = $('#img'); var width = $img.width(); var height = $img.height(); domtoimage.toPng($('html')[0]) .then(function (blob) { var pdf = new jsPDF('p', 'mm', 'a4'); var imgProps = pdf.getImageProperties(blob); var pdfWidth = pdf.internal.pageSize.width; var pdfHeight = pdf.internal.pageSize.height; var widthRatio = pdfWidth / width; var heightRatio = pdfHeight / height; var ratio = Math.min(widthRatio, heightRatio); var w = imgProps.width * ratio; var h = imgProps.height * ratio; pdf.addImage(blob, 'PNG', 0, 0, w, h); pdf.save('allPage.pdf'); }) .catch(function(error) { console.error('导出失败:', error); }) .finally(function() { // 无论成功失败,隐藏加载器并启用按钮 $('#loader').hide(); $('#export').prop('disabled', false); }); } " ui <- fluidPage( tags$head( tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"), tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js"), tags$script(HTML(js)), tags$style(HTML(" #loader { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 9999; } .loader-content { color: white; font-size: 18px; text-align: center; } .loader-spinner { border: 4px solid rgba(255, 255, 255, 0.3); border-top: 4px solid white; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 10px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } ")) ), # 加载器元素,默认隐藏 div(id = "loader", style = "display: none;", div(class = "loader-content", div(class = "loader-spinner"), "正在导出PDF,请稍候..." ) ), # 背景图片 tags$img(id = "img", src = "http://upload.wikimedia.org/wikipedia/commons/5/5d/AaronEckhart10TIFF.jpg", style = 'position: absolute; width: 1250px; height: 880px;'), div( id = "container1", style = "position: absolute; left: 30px; top: 170px; display: inline-block; vertical-align: middle; width: 300px;", actionButton("export", "Export to PDF", onclick = "Export();") ) ) server <- function(input, output, session) { } shinyApp(ui, server)
关键修改说明
- 加载器UI与样式:新增全屏半透明加载层,包含旋转动画和提示文本,通过CSS设置层级置顶,确保覆盖所有页面内容,清晰提示用户当前处于加载状态。
- JS逻辑优化:
- 导出开始时立即显示加载器,并禁用导出按钮,防止重复触发操作
- 使用
finally回调统一处理加载器隐藏和按钮启用,无论导出成功或失败,都能恢复页面正常状态 - 添加
catch回调捕获导出过程中的错误,便于调试排查问题
- 无额外依赖:纯前端实现,无需修改服务器端逻辑,完美适配原有JS导出流程
内容的提问来源于stack exchange,提问作者TarJae
相关产品推荐
相关产品推荐

