如何根据选中的标签页切换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)
方案说明
- 只初始化一次按钮和tippy:侧边栏只保留一个信息按钮,并且只调用一次
tippy_this完成tooltip的初始化,避免重复创建实例。 - 使用shinyjs调用Tippy的JS API:Tippy提供了
setContent方法可以动态修改提示内容,通过runjs将当前选中标签对应的提示文本传递给前端,实现动态更新。 - 维护性提升:如果需要新增标签或修改提示文本,只需要修改
tip_texts列表即可;修改按钮样式或tippy参数时,只需要修改一处代码。
内容的提问来源于stack exchange,提问作者king_of_limes
相关产品推荐
相关产品推荐

