Shiny中DT表格scrollY模式下宽度变化后表头错位问题及解决需求
DT表格宽度切换后表头错位的修复方案(手动触发重排)
我在Shiny应用中使用shinyjs的addClass()和removeClass()方法,通过显示/隐藏侧边面板来切换DT datatable的宽度。表格启用了scrollY属性,已知该属性可能引发表头错位问题,在宽度扩大时确实出现了此问题。
发现点击表头进行排序时会触发一次重排操作,可修复错位;实际应用中点击表格行也会触发重排(当前示例未复现,原因未知)。如果没有直接修复错位的方案,请问如何通过JavaScript手动触发表头点击时的重排操作?
require(shiny) require(shinyjs) require(DT) shiny::shinyApp( ui = fluidPage( shinyjs::useShinyjs(), shinyjs::inlineCSS(list(.wide = "width: 96%; margin-left: 2%; margin-right: 2%;")), shinyjs::inlineCSS(list(.narrow = "width: 70%; margin-left: 2%;")), actionButton(inputId = "show_hide_button", label = "Show/hide"), fluidRow( div( id = "side_panel", style = "display: inline-block; width: 25%; vertical-align: top;", h3("Collapsible panel") ), div( id = "main_panel", class = "narrow", style = "display: inline-block; vertical-align: top;", DT::dataTableOutput("my_table") ) ) ), server = function(input, output, session) { output$my_table <- DT::renderDataTable({ DT::datatable( data = mtcars, options = list( scrollY = 480, scrollCollapse = T ) ) }) observeEvent(input$show_hide_button, { if(input$show_hide_button %% 2 == 0) { shinyjs::removeClass(id = "main_panel", class = "wide") shinyjs::addClass(id = "main_panel", class = "narrow") shinyjs::show("side_panel") } else { shinyjs::hide("side_panel") shinyjs::removeClass(id = "main_panel", class = "narrow") shinyjs::addClass(id = "main_panel", class = "wide") } }) } )
初始视图
表格宽度扩大后表头错位
点击'mpg'列排序后错位修复
手动触发重排的解决方案
DT表格提供了内置API可以直接触发重排或列宽调整,无需模拟表头点击,以下是两种有效方法:
1. 调用columns.adjust()适配列宽
这是修复表头错位最精准的方式,会重新计算列宽以适配当前容器尺寸,同时保留表格的排序、分页状态:
$('#my_table').DataTable().columns.adjust().draw(false);
columns.adjust():重新计算所有列的宽度draw(false):重绘表格但不重置当前的排序、分页等状态
2. 调用draw()触发完整重绘
如果需要完全模拟点击表头后的重排效果,可以直接调用表格的draw()方法,该方法会重新渲染整个表格:
$('#my_table').DataTable().draw();
在Shiny应用中集成
修改observeEvent逻辑,在切换完表格宽度类名后执行上述JavaScript代码:
observeEvent(input$show_hide_button, { if(input$show_hide_button %% 2 == 0) { shinyjs::removeClass(id = "main_panel", class = "wide") shinyjs::addClass(id = "main_panel", class = "narrow") shinyjs::show("side_panel") shinyjs::runjs("$('#my_table').DataTable().columns.adjust().draw(false);") } else { shinyjs::hide("side_panel") shinyjs::removeClass(id = "main_panel", class = "narrow") shinyjs::addClass(id = "main_panel", class = "wide") shinyjs::runjs("$('#my_table').DataTable().columns.adjust().draw(false);") } })
完整修改后的代码
require(shiny) require(shinyjs) require(DT) shiny::shinyApp( ui = fluidPage( shinyjs::useShinyjs(), shinyjs::inlineCSS(list(.wide = "width: 96%; margin-left: 2%; margin-right: 2%;")), shinyjs::inlineCSS(list(.narrow = "width: 70%; margin-left: 2%;")), actionButton(inputId = "show_hide_button", label = "Show/hide"), fluidRow( div( id = "side_panel", style = "display: inline-block; width: 25%; vertical-align: top;", h3("Collapsible panel") ), div( id = "main_panel", class = "narrow", style = "display: inline-block; vertical-align: top;", DT::dataTableOutput("my_table") ) ) ), server = function(input, output, session) { output$my_table <- DT::renderDataTable({ DT::datatable( data = mtcars, options = list( scrollY = 480, scrollCollapse = TRUE ) ) }) observeEvent(input$show_hide_button, { if(input$show_hide_button %% 2 == 0) { shinyjs::removeClass(id = "main_panel", class = "wide") shinyjs::addClass(id = "main_panel", class = "narrow") shinyjs::show("side_panel") shinyjs::runjs("$('#my_table').DataTable().columns.adjust().draw(false);") } else { shinyjs::hide("side_panel") shinyjs::removeClass(id = "main_panel", class = "narrow") shinyjs::addClass(id = "main_panel", class = "wide") shinyjs::runjs("$('#my_table').DataTable().columns.adjust().draw(false);") } }) } )
内容的提问来源于stack exchange,提问作者Ben Ernest
相关产品推荐
相关产品推荐

