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

如何用DRY方式在Shiny中结合shinyjs与bslib实现卡片显隐

优化Shiny卡片显隐逻辑,遵循DRY原则

现有一款Shiny原型应用,可通过input$checkbox实现卡片的显隐切换,但代码存在大量重复逻辑,不符合DRY(Don't Repeat Yourself)原则,难以扩展和维护。需要抽象重复的if ("cardXX" %in% input$checkbox) show("cardXX") else hide("cardXX")调用,同时处理input$checkbox为空时的批量隐藏操作。

原型代码

library(shiny)
library(tidyverse)
library(bslib)
library(shinyjs)

cards <- list(
  card(
    id = "card1",
    card_header("Card 1"),
    plotOutput("card1_plot")
  ),
  card(
    id = "card2",
    card_header("Card 2"),
    plotOutput("card2_plot")
  ),
  card(
    id = "card3",
    card_header("Card 3"),
    plotOutput("card3_plot")
  ),
  card(
    id = "card4",
    card_header("Card 4"),
    plotOutput("card4_plot")
  )
)

ui <- page_sidebar(
  useShinyjs(),
  title = "My Dashboard",
  sidebar = sidebar(
    "Controls",
    checkboxGroupInput("checkbox", "Select Stuff", 
                       choices = c("card1", "card2", "card3", "card4"), 
                       selected = c("card1", "card2", "card3", "card4"))
  ),
  "Main Content Area",
  fillable = FALSE,
  cards
)

server <- function(input, output) {
  
  observeEvent(input$checkbox, {
    if (is.null(input$checkbox)) hide("card1"); hide("card2"); hide("card3"); hide("card4");
    if ("card1" %in% input$checkbox) show("card1") else hide("card1")
    if ("card2" %in% input$checkbox) show("card2") else hide("card2")
    if ("card3" %in% input$checkbox) show("card3") else hide("card3")
    if ("card4" %in% input$checkbox) show("card4") else hide("card4")
  }, ignoreNULL = FALSE)
  
}

shinyApp(ui = ui, server = server)

应用效果:
卡片显隐切换效果

优化后的代码

library(shiny)
library(tidyverse)
library(bslib)
library(shinyjs)

# 统一管理所有卡片ID,后续新增/删除卡片只需修改此处
card_ids <- c("card1", "card2", "card3", "card4")

# 批量生成卡片,避免重复编写card()代码
cards <- map(card_ids, function(id) {
  card(
    id = id,
    card_header(str_replace(id, "card", "Card ")),
    plotOutput(paste0(id, "_plot"))
  )
})

ui <- page_sidebar(
  useShinyjs(),
  title = "My Dashboard",
  sidebar = sidebar(
    "Controls",
    checkboxGroupInput("checkbox", "Select Stuff", 
                       choices = card_ids, 
                       selected = card_ids)
  ),
  "Main Content Area",
  fillable = FALSE,
  cards
)

server <- function(input, output) {
  
  observeEvent(input$checkbox, {
    # 遍历所有卡片ID,统一处理显隐逻辑
    walk(card_ids, function(id) {
      if (id %in% input$checkbox) {
        show(id)
      } else {
        hide(id)
      }
    })
  }, ignoreNULL = FALSE)
  
}

shinyApp(ui = ui, server = server)

优化说明

  1. 集中管理卡片ID:将所有卡片ID存入card_ids向量,避免多处硬编码,后续调整卡片数量只需修改这个向量。
  2. 批量生成UI组件:用map()函数遍历卡片ID批量生成卡片,卡片标题、输出ID通过字符串处理动态生成,彻底消除重复的card()定义。
  3. 抽象显隐逻辑:用walk()遍历所有卡片ID,统一执行显隐判断逻辑,替代原来重复的if-else语句。当input$checkbox为空时,所有卡片自动进入隐藏分支,无需单独编写空值处理代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:42:54