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

如何根据选中的标签页切换tippy提示框内容?

动态更新Shiny侧边栏按钮的Tippy提示文本(基于当前TabBox标签页)

我开发了一个使用shinydashboard侧边栏与tabBox多标签页的Shiny应用,希望侧边栏的信息按钮在鼠标悬停时,根据当前选中的标签页显示不同提示文本。

目前有一个可行但维护性差的方案:为每个标签页定义样式相同但提示文本不同的信息按钮,代码如下:

library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(tippy)

ui <- dashboardPage(
  skin = 'blue',
  dashboardHeader(),
  dashboardSidebar(width = 275,
                   sidebarMenu(conditionalPanel(condition = "input.my_tabbox == 'panel_1'",
                                                actionBttn(inputId = "info_button",label = NULL,style = 'material-circle',color = 'primary',
                                                           icon = icon('info')),
                                                tippy_this("info_button",tooltip = "You are on panel 1",trigger = 'mouseenter focus',
                                                           placement = 'right')),
                               conditionalPanel(condition = "input.my_tabbox == 'panel_2'",
                                                actionBttn(inputId = "info_button_2",label = NULL,style = 'material-circle',color = 'primary',
                                                           icon = icon('info')),
                                                tippy_this("info_button_2",tooltip = "You are on panel 2",trigger = 'mouseenter focus',
                                                           placement = 'right')))),

  dashboardBody(
    fluidRow(column(width = 12,
                    tabBox(width = 12,id = "my_tabbox",
                           tabPanel(title = "Panel 1",value = "panel_1"),
                           tabPanel(title = "Panel 2",value = "panel_2"))))
  )
)

server <- function(input,output){}
shinyApp(ui = ui,server = server)

但这个方案的问题在于,修改按钮样式或行为时需要对每个标签页重复操作,维护成本高。我尝试用renderUI封装tippy_this实现动态修改提示文本,但未成功,尝试代码如下:

ui <- dashboardPage(
  skin = 'blue',
  dashboardHeader(),
  dashboardSidebar(width = 275,
                   sidebarMenu(actionBttn(inputId = "info_button",label = NULL,style = 'material-circle',color = 'primary',icon = icon('info')),
                               uiOutput("my_tippy"))),
  dashboardBody(
    fluidRow(column(width = 12,
                    tabBox(width = 12,id = "my_tabbox",
                           tabPanel(title = "Panel 1",value = "panel_1"),
                           tabPanel(title = "Panel 2",value = "panel_2"))))
  )
)

get_tippy_sentence <- function(tabbox_input){
  if(tabbox_input == "panel_1"){
    return("You are on panel 1")
  }else if(tabbox_input == "panel_2"){
    return("You are on panel 2")
  }
}

server <- function(input,output){
  
  output$my_tippy <- renderUI({
    tippy_this("info_button",tooltip = get_tippy_sentence(input$my_tabbox),trigger = 'mouseenter focus',placement = 'right')
  })
}

我还尝试将提示文本设为响应式对象,并通过observeEvent监听tabBox切换,但所有尝试均未能实现第二标签页的提示文本切换。


优雅的解决方案:利用Tippy的JS API动态更新提示内容

问题的核心在于,直接重复调用tippy_this不会替换已存在的tooltip实例,而是会叠加,导致新的提示无法生效。我们可以只初始化一次tippy,然后通过Shiny的runjs函数调用Tippy的setContent方法,根据当前选中的标签页动态更新提示文本。

完整代码如下:

library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(tippy)
library(shinyjs) # 需要用到runjs函数

ui <- dashboardPage(
  skin = 'blue',
  dashboardHeader(),
  dashboardSidebar(width = 275,
                   sidebarMenu(
                     # 只定义一次按钮
                     actionBttn(inputId = "info_button", label = NULL, 
                                style = 'material-circle', color = 'primary',
                                icon = icon('info')),
                     # 初始化tippy,初始提示可以设为空或默认文本
                     tippy_this("info_button", tooltip = "", 
                                trigger = 'mouseenter focus', placement = 'right')
                   )),
  dashboardBody(
    useShinyjs(), # 必须加载shinyjs
    fluidRow(column(width = 12,
                    tabBox(width = 12, id = "my_tabbox",
                           tabPanel(title = "Panel 1", value = "panel_1"),
                           tabPanel(title = "Panel 2", value = "panel_2"))))
  )
)

# 定义提示文本映射
tip_texts <- list(
  panel_1 = "You are on panel 1",
  panel_2 = "You are on panel 2"
)

server <- function(input, output, session){
  
  # 监听tabBox切换事件,更新tooltip内容
  observeEvent(input$my_tabbox, {
    current_tip <- tip_texts[[input$my_tabbox]]
    # 调用Tippy的setContent方法更新提示
    runjs(sprintf('tippy("#info_button").setContent("%s")', current_tip))
  }, ignoreInit = FALSE) # ignoreInit=FALSE确保初始加载也会设置正确的提示
}

shinyApp(ui = ui, server = server)

方案说明

  1. 只初始化一次按钮和tippy:侧边栏只保留一个信息按钮,并且只调用一次tippy_this完成tooltip的初始化,避免重复创建实例。
  2. 使用shinyjs调用Tippy的JS API:Tippy提供了setContent方法可以动态修改提示内容,通过runjs将当前选中标签对应的提示文本传递给前端,实现动态更新。
  3. 维护性提升:如果需要新增标签或修改提示文本,只需要修改tip_texts列表即可;修改按钮样式或tippy参数时,只需要修改一处代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 22:58:10