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

使用shinyjs隐藏图表后,如何隐藏shinycssloaders的Spinner加载动画?

解决Shiny动态显示/隐藏图表时Spinner残留问题

问题根源

调整numberOfPlotsToShow时,所有三个renderPlot都会因输入值变化重新执行——即使p3已被shinyjs::hide()隐藏,它对应的渲染逻辑仍会触发,导致spinner3被激活并残留。hideSpinner()无效是因为Spinner的显示状态绑定到了plot的渲染流程,单纯调用隐藏方法无法阻断渲染触发的Spinner显示。

解决方案

推荐两种可靠的解决方式,按需选择:

方案1:用conditionalPanel从UI层控制元素渲染

直接让图表和Spinner仅在满足显示条件时才出现在DOM中,从根源避免不必要的Spinner触发:

library(shiny)
library(ggplot2)
library(shinycssloaders)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  numericInput("numberOfPlotsToShow", label = "number of plots to show", value = 1),
  # 仅当显示数量≥1时渲染p1及对应的Spinner
  conditionalPanel(
    condition = "input.numberOfPlotsToShow >= 1",
    plotOutput("p1", height = "150px") |> withSpinner(id = "spinner1")
  ),
  # 仅当显示数量≥2时渲染p2及对应的Spinner
  conditionalPanel(
    condition = "input.numberOfPlotsToShow >= 2",
    plotOutput("p2", height = "150px") |> withSpinner(id = "spinner2")
  ),
  # 仅当显示数量≥3时渲染p3及对应的Spinner
  conditionalPanel(
    condition = "input.numberOfPlotsToShow >= 3",
    plotOutput("p3", height = "150px") |> withSpinner(id = "spinner3")
  )
)

server <- function(input, output, session) {
  base_plot <- ggplot(iris) + geom_point(aes(x=Sepal.Width, y=Sepal.Length))
  
  output$p1 <- renderPlot({
    base_plot + ggtitle(input$numberOfPlotsToShow)
  })
  
  output$p2 <- renderPlot({
    base_plot + ggtitle(input$numberOfPlotsToShow)
  })
  
  output$p3 <- renderPlot({
    base_plot + ggtitle(input$numberOfPlotsToShow)
  })
}

shinyApp(ui, server, options = list(launch.browser = TRUE))

方案2:用req()控制渲染逻辑+同步隐藏Spinner

如果不想修改UI结构,可以在renderPlot中加入条件判断,仅当图表需要显示时才执行渲染,同时用shinyjs同步隐藏/显示Spinner:

library(shiny)
library(ggplot2)
library(shinycssloaders)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  numericInput("numberOfPlotsToShow", label = "number of plots to show", value = 1),
  plotOutput("p1", height = "150px") |> withSpinner(id = "spinner1"),
  plotOutput("p2", height = "150px") |> withSpinner(id = "spinner2"),
  plotOutput("p3", height = "150px") |> withSpinner(id = "spinner3")
)

server <- function(input, output, session) {
  base_plot <- ggplot(iris) + geom_point(aes(x=Sepal.Width, y=Sepal.Length))
  
  output$p1 <- renderPlot({
    # 仅当显示数量≥1时才执行渲染
    req(input$numberOfPlotsToShow >= 1)
    base_plot + ggtitle(input$numberOfPlotsToShow)
  })
  
  output$p2 <- renderPlot({
    req(input$numberOfPlotsToShow >= 2)
    base_plot + ggtitle(input$numberOfPlotsToShow)
  })
  
  output$p3 <- renderPlot({
    req(input$numberOfPlotsToShow >= 3)
    base_plot + ggtitle(input$numberOfPlotsToShow)
  })
  
  observeEvent(input$numberOfPlotsToShow, {
    N <- input$numberOfPlotsToShow
    for (ii in 1:3) {
      plot_id <- paste0("p", ii)
      spinner_id <- paste0("spinner", ii)
      if (ii <= N) {
        shinyjs::show(plot_id)
        shinyjs::show(spinner_id)
      } else {
        shinyjs::hide(plot_id)
        shinyjs::hide(spinner_id)
      }
    }
  })
}

shinyApp(ui, server, options = list(launch.browser = TRUE))

说明

  • 方案1更简洁,直接通过UI条件控制元素存在性,无需额外的observeEvent处理显示/隐藏逻辑。
  • 方案2保留原UI结构,通过req()阻断不必要的渲染,同时同步控制Spinner的显示状态,避免残留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:50:18