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

Shiny应用:点击actionButton后触发shinycustomloader加载效果

解决Shiny应用中仅点击按钮触发加载动画且每次点击都生效的问题

我明白你的问题:你希望只有在用户点击Submit按钮时才显示加载界面,而且每次点击都要触发加载动画,而不是只第一次有效。之前用conditionalPanel("input.submit==1")的问题在于,input.submit的值是累加的——第一次点击是1,第二次是2,第三次是3……所以后续点击时条件不再满足,加载界面就不显示了。

下面是两种可行的解决方案,都能实现你的需求:


方案1:使用reactiveVal跟踪加载状态

这种方法通过一个响应式变量来控制加载状态,每次点击按钮时先标记为"加载中",数据处理完成后标记为"加载完成",这样就能确保每次点击都触发加载动画。

修改后的完整代码

ui.R

library(shiny)
library(shinydashboard)
library(DT)
library(shinycustomloader)

dashboardPage(
  dashboardHeader(),
  dashboardSidebar(
    selectizeInput("file", "Select File", c("fileA", "fileB")),
    actionButton("submit", "Submit")
  ),
  dashboardBody(
    fluidRow(
      box(
        h2("My Data"),
        # 根据加载状态显示不同内容
        conditionalPanel(
          condition = "output.isLoading",
          div(style = 'overflow-x: scroll', withLoader(DT::dataTableOutput('mytable'), type = "html", loader = "loader1"))
        ),
        conditionalPanel(
          condition = "!output.isLoading && output.hasData",
          div(style = 'overflow-x: scroll', DT::dataTableOutput('mytable'))
        ),
        width = 12
      )
    )
  )
)

server.R

library(shiny)
library(shinydashboard)
library(DT)

shinyServer(function(input, output, session) {
  # 初始化响应式变量:跟踪加载状态和是否有数据
  is_loading <- reactiveVal(FALSE)
  has_data <- reactiveVal(FALSE)
  matched_df <- reactiveVal(NULL)
  
  # 点击Submit按钮时触发
  observeEvent(input$submit, {
    # 标记为加载中
    is_loading(TRUE)
    has_data(FALSE)
    
    # 模拟数据处理(替换成你的实际代码)
    Sys.sleep(2) # 模拟耗时操作
    file_name <- req(input$file)
    # open_file <- read_excel(paste0("input_files/", file_name))
    # 这里替换成你的数据处理逻辑
    temp_df <- data.frame(A = c(1, 2, 3, 4), B = c("A", "B", "C", "D"))
    
    # 处理完成后更新数据,标记加载完成
    matched_df(temp_df)
    is_loading(FALSE)
    has_data(TRUE)
  })
  
  # 为UI的conditionalPanel提供输出值
  output$isLoading <- reactive({
    is_loading()
  })
  outputOptions(output, "isLoading", suspendWhenHidden = FALSE)
  
  output$hasData <- reactive({
    has_data()
  })
  outputOptions(output, "hasData", suspendWhenHidden = FALSE)
  
  # 渲染数据表
  output$mytable = DT::renderDataTable({
    req(matched_df())
    matched_df()
  })
})

方案2:直接控制withLoader的显示(更简洁)

另一种方法是利用shinycustomloader的condition参数,结合按钮点击的次数来触发加载,同时确保每次点击都能重新触发。

修改后的UI部分

dashboardBody(
  fluidRow(
    box(
      h2("My Data"),
      div(style = 'overflow-x: scroll', 
          withLoader(
            DT::dataTableOutput('mytable'), 
            type = "html", 
            loader = "loader1",
            # 条件:按钮点击次数大于0,且数据表正在渲染
            condition = "input.submit > 0 && !output.mytable"
          )
      ),
      width = 12
    )
  )
)

对应的Server调整

只需要确保每次点击按钮时,数据表的渲染会重新触发(你的现有代码已经做到了,不过建议把selected改成reactiveVal,避免在observeEvent里定义reactive):

shinyServer(function(input, output, session) {
  selected <- reactiveVal(NULL)
  
  observeEvent(input$submit, {
    # 模拟数据处理
    Sys.sleep(2)
    matched_df <- data.frame(A = c(1, 2, 3, 4), B = c("A", "B", "C", "D"))
    selected(matched_df)
  })
  
  output$mytable = DT::renderDataTable({
    req(selected())
    selected()
  })
})

关键说明

  • 方案1的优势是更灵活,可以精确控制加载状态和空白界面的显示逻辑;
  • 方案2更简洁,利用shinycustomloader自带的condition参数,不需要额外的reactiveVal;
  • 两种方案都解决了input.submit累加导致的条件失效问题,确保每次点击按钮都会触发加载动画。

内容的提问来源于stack exchange,提问作者Kasia Kulma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:56:25