shinydashboard多menuSubItem指向同一tabItem并更新tabBox相关问题咨询
修复方案
核心修正点
- 子菜单选中高亮问题:shinydashboard默认通过
tabName匹配第一个元素做高亮,相同tabName下需要手动控制选中样式,点击时清除同组子菜单的选中状态,为当前点击项添加选中属性和样式。 - 动态渲染菜单JS失效问题:原写法是页面加载时直接绑定事件到
a[data-toggle=tab]元素,动态生成的元素不会被绑定,改为事件委托绑定到document即可适配所有动态加载的菜单元素。
修正后的完整代码(同时适配静态/动态菜单)
library(shiny) library(shinydashboard) library(shinyjs) # 修正后的JS代码 tabs_js <- '$(document).on("click", "a[data-toggle=tab]", function(){ // 处理tabBox同步的逻辑 var el = $(this).text().trim(); Shiny.setInputValue("activeTab", el); // 处理子菜单选中高亮的逻辑 if($(this).parent().hasClass("treeview-menu")){ // 先清除所有同层级子菜单的选中状态 $(this).parents("ul.treeview-menu").find("li").removeClass("active"); $(this).parents("ul.treeview-menu").find("a").attr("aria-selected", "false"); // 给当前点击的子菜单加选中状态 $(this).parent().addClass("active"); $(this).attr("aria-selected", "true"); } })' ui <- dashboardPage( dashboardHeader(), dashboardSidebar( sidebarMenu(id = "side_id", menuItem("Boxes", tabName = "boxes", selected = T), # 静态菜单写法 # menuItem("Foxes", tabName = "foxes", # menuSubItem("Loxes", tabName = "loxes"), # menuSubItem("Roxes", tabName = "loxes"), # menuSubItem("Noxes", tabName = "loxes") # ), # 动态菜单写法,和上面静态写法二选一即可 menuItemOutput("fox_menu"), verbatimTextOutput("selected_tab_text") )), dashboardBody( useShinyjs(), tags$head( tags$script(HTML(tabs_js)) ), tabItems( tabItem(tabName = "boxes", tabBox( tabPanel("One") )), tabItem(tabName = "foxes"), tabItem(tabName = "loxes", tabBox(id = "lox_box", tabPanel("A"), tabPanel("B"), tabPanel("C") ) ) ) ) ) server <- function(session, input, output) { observeEvent(input$activeTab,{ switch(input$activeTab, "Loxes" = updateTabItems(session, "lox_box", "A"), "Roxes" = updateTabItems(session, "lox_box", "B"), "Noxes" = updateTabItems(session, "lox_box", "C") ) }) # 动态渲染菜单的逻辑,用静态菜单的话可以注释掉这部分 output$fox_menu <- renderMenu({ menuItem("Foxes", tabName = "foxes", menuSubItem("Loxes", tabName = "loxes"), menuSubItem("Roxes", tabName = "loxes"), menuSubItem("Noxes", tabName = "loxes") ) }) output$selected_tab_text <- renderPrint({ input$activeTab }) } shinyApp(ui = ui, server = server)
其他优化点
原逻辑里的observeEvent可以用switch代替多层if else,代码更简洁易维护。如果后续需要新增子菜单,只需要加一行switch的分支即可。
内容的提问来源于stack exchange,提问作者Alan Farahani
相关产品推荐
相关产品推荐

