如何更新DataTable时保留滚动位置?Shiny+DT开发问题
问题1:DT更新时保持滚动位置
解决方案思路
replaceData() 会触发表格重绘,导致滚动位置重置。需要手动记录更新前的滚动位置,在表格更新完成后恢复该位置。
修改后的完整代码
library(shiny) library(DT) ui <- fluidPage( # 添加自定义JS用于保存和恢复滚动位置 tags$script(HTML(" // 获取当前滚动位置并发送给Shiny Shiny.addCustomMessageHandler('getScrollPosition', function(message) { var scrollBody = $('#' + message.id).find('.dataTables_scrollBody'); Shiny.setInputValue(message.id + '_scrollTop', scrollBody.scrollTop()); Shiny.setInputValue(message.id + '_scrollLeft', scrollBody.scrollLeft()); }); // 恢复之前保存的滚动位置 Shiny.addCustomMessageHandler('restoreScrollPosition', function(message) { var scrollBody = $('#' + message.id).find('.dataTables_scrollBody'); // 延迟执行确保表格已完成更新 setTimeout(function() { scrollBody.scrollTop(Shiny.inputBindings.bindingNames['shiny.action'].getValue(message.id + '_scrollTop')); scrollBody.scrollLeft(Shiny.inputBindings.bindingNames['shiny.action'].getValue(message.id + '_scrollLeft')); }, 100); }); ")), DTOutput("graph_table_1") ) server <- function(input, output, session) { graph_data_1 <- reactiveVal(data.frame( A = 1:10, B = rnorm(10), C = rnorm(10), D = rnorm(10), E = rnorm(10), F = rnorm(10), G = rnorm(10), H = rnorm(10) )) # 创建DT代理 proxy <- dataTableProxy("graph_table_1") output$graph_table_1 <- renderDT({ datatable( graph_data_1(), selection = list(target = "cell"), options = list(scrollX = TRUE, scrollY = "300px", paging = FALSE, searching = FALSE, stateSave = FALSE) ) }) observeEvent(input$graph_table_1_cells_selected, { selected_cells <- input$graph_table_1_cells_selected if (nrow(selected_cells) > 0) { temp_data <- graph_data_1() for (cell in 1:nrow(selected_cells)) { row <- selected_cells[cell, 1] col <- selected_cells[cell, 2] if (row <= nrow(temp_data) && col <= ncol(temp_data)) { temp_data[row, col] <- NA } } # 1. 记录当前滚动位置 session$sendCustomMessage(type = "getScrollPosition", message = list(id = "graph_table_1")) # 2. 更新数据源 graph_data_1(temp_data) # 3. 更新表格内容 replaceData(proxy, temp_data, resetPaging = FALSE) # 4. 恢复滚动位置 session$sendCustomMessage(type = "restoreScrollPosition", message = list(id = "graph_table_1")) } }) } shinyApp(ui, server)
关键修改说明
- 新增JS代码:通过自定义消息处理器获取表格滚动容器的
scrollTop和scrollLeft值,保存为Shiny输入变量;更新完成后再读取这些值恢复滚动位置。 - 延迟执行恢复操作:用
setTimeout确保表格完成重绘后再设置滚动位置,避免无效操作。
问题2:修复无法运行的DT渲染代码
问题原因
代码中直接在格式化函数里调用响应式对象graph_data_test_1(),未做隔离处理,且重复调用可能导致依赖混乱;同时列名处理逻辑存在潜在问题。
修复后的代码
output$test_graph_table_1 <- renderDT({ # 先隔离响应式数据,避免不必要的重绘触发 data <- isolate(graph_data_test_1()) datatable( data, editable = TRUE, selection = list(target = 'cell'), options = list( dom = 't', paging = FALSE, scrollY = "600px", scrollX = TRUE, scrollCollapse = TRUE, columnDefs = list( list(className = 'dt-center', targets = '_all') ) ), rownames = FALSE, class = 'cell-border stripe' ) %>% formatStyle( columns = names(data), # 使用隔离后的数据集列名 backgroundColor = '#000000', color = '#FFFFFF' ) %>% formatPercentage( columns = setdiff(names(data)[-1], "time"), # 基于隔离数据处理列筛选 digits = 2 ) })
关键修复点
- 提前隔离响应式数据:将
isolate(graph_data_test_1())赋值给变量data,后续所有列名引用都基于该变量,避免重复调用响应式对象。 - 统一列名来源:格式化函数的
columns参数使用隔离后数据集的列名,避免因响应式依赖导致的渲染错误。 - 优化列筛选逻辑:确保
setdiff操作基于实际存在的列名,减少潜在报错风险。
内容的提问来源于stack exchange,提问作者Unknown
相关产品推荐
相关产品推荐

