You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiny withProgress进度条关闭图标隐藏及点击状态检测咨询

解决Shiny进度条关闭按钮导致UI无响应问题

方案1:直接隐藏关闭按钮(最简实现)

你提到的style="old"参数确实可以直接禁用关闭按钮,如果你想保留新版进度条的样式,也可以通过全局CSS隐藏所有进度通知的关闭按钮,只需要在UI的dashboardBody开头添加如下代码即可:

shiny::tags$head(
  shiny::tags$style(HTML("
    .shiny-notification-close {
      display: none !important;
    }
  "))
)

该方案不需要修改业务逻辑,适合不需要取消功能的场景。

方案2:实现点击关闭按钮取消长耗时任务

你之前的JS代码失效是因为事件绑定的时候进度条还没有渲染到页面上,动态生成的元素无法直接绑定点击事件,需要把事件委托到全局的document对象上,同时需要把长耗时任务改成可中断的模式,具体修改如下:

步骤1:UI引入shinyjs并添加事件监听

首先在UI的dashboardBody里添加shinyjs初始化和事件监听代码:

body=shinydashboard::dashboardBody(
  shinyjs::useShinyjs(), # 初始化shinyjs
  shiny::tags$script(HTML("
    // 把关闭按钮点击事件委托到document,适配动态生成的进度条
    $(document).on('click', '.shiny-notification-close', function() {
      Shiny.setInputValue('pb_close_click', Math.random()); // 用随机值保证每次点击都能触发R端响应
    });
  ")),
  # 其余原有UI代码不变
)

步骤2:修改长耗时函数支持中断

给long_run_op增加一个检查取消状态的回调参数:

long_run_op <- function(num_iter, verbose=TRUE, cancel_check = function(){FALSE}) {
  for (x in 1:num_iter) {
    # 每次循环先检查是否触发了取消
    if(cancel_check()) {
      if(verbose) message("task cancelled by user.")
      return(NULL)
    }
    if(verbose) message("working... [value=",x,"]")
    Sys.sleep(0.5)
  }
  if(verbose) message("calculation finished.")
  return(rnorm(num_iter))
}

步骤3:修改server逻辑支持取消

server <- function(input, output, session) {
  # 存储任务取消状态
  task_cancelled <- shiny::reactiveVal(FALSE)
  
  # 监听关闭按钮点击事件
  shiny::observeEvent(input$pb_close_click, {
    task_cancelled(TRUE)
  })
  
  shiny::observeEvent(input$run, {
    # 每次运行前重置取消状态
    task_cancelled(FALSE)
    
    shiny::withProgress(
      withCallingHandlers(
        out <- long_run_op(
          num_iter=input$num_iter,
          verbose=TRUE,
          # 传入取消检查函数
          cancel_check = function() task_cancelled()
        ),
        message=function(m) if(grepl("\\[value=[0-9]+\\]", m$message)) {
          val <- as.numeric(gsub(".*\\[value=([0-9]+)\\].*$", "\\1", m$message))
          shiny::setProgress(value=val)
        }
      ),
      message="working...",
      max=input$num_iter,
      value=0
    )
    # 只有任务没取消的时候才渲染结果
    if(!is.null(out)) {
      output$result <- shiny::renderPlot(plot(out))
    } else {
      # 可以加个提示告知用户任务已取消
      shiny::showNotification("任务已被取消", type = "warning")
    }
  })
}

该方案既保留了进度条的关闭按钮,又能实现用户主动取消长耗时任务,避免UI假死。

内容的提问来源于stack exchange,提问作者Karsten W.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 09:12:00