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

如何在R Shiny的DT datatable中实现父行折叠展示子行功能

R Shiny DT 父子行(可变子行数)实现方案

直接运行下方完整代码即可实现需求:父ID仅展示1次,对应子行默认隐藏,点击父行可展开/收起子行,自动适配0到任意数量的子行,不需要修改JS逻辑。

依赖安装

如果没有安装所需依赖,先运行以下命令安装:

install.packages(c("shiny", "DT", "dplyr"))

完整可运行代码

library(shiny)
library(DT)
library(dplyr)

# --------------------------
# 可替换为你自己的业务数据
# --------------------------
df = data.frame(
  parentID = c("parent1","parent1","parent2","parent3","parent4","parent4","parent4"),
  childID = c("childA","childB","childC","childD","childE","childF","childG"),
  childDesc = c("desc1","desc2","desc3","desc4","desc5","desc6","desc7")
)

# --------------------------
# 固定预处理逻辑 无需修改
# --------------------------
parent_df = df %>% distinct(parentID)
parent_df$child_data = lapply(parent_df$parentID, function(pid){
  df %>% filter(parentID == pid) %>% select(-parentID)
})

# --------------------------
# 固定JS回调逻辑 无需修改
# --------------------------
callback_js = JS(
  "table.on('click', 'td.details-control', function() {",
  "  var tr = $(this).closest('tr');",
  "  var row = table.row(tr);",
  "  if (row.child.isShown()) {",
  "    row.child.hide();",
  "    tr.removeClass('shown');",
  "  } else {",
  "    row.child(format(row.data().child_data)).show();",
  "    tr.addClass('shown');",
  "  }",
  "});",
  "function format(d) {",
  "  if (d.length == 0) return '<span style=\"padding-left:50px;\">无对应子行</span>';",
  "  var table = '<table cellpadding=\"5\" cellspacing=\"0\" border=\"0\" style=\"padding-left:50px;\">'+",
  "    '<thead><tr><th>子项ID</th><th>子项描述</th></tr></thead><tbody>';",
  "  for (var i = 0; i < d.length; i++) {",
  "    table += '<tr>' +",
  "      '<td>' + d[i].childID + '</td>' +",
  "      '<td>' + d[i].childDesc + '</td>' +",
  "    '</tr>';",
  "  }",
  "  table += '</tbody></table>';",
  "  return table;",
  "}"
)

# --------------------------
# Shiny界面与渲染逻辑
# --------------------------
ui <- fluidPage(
  DTOutput("dt_table")
)

server <- function(input, output) {
  output$dt_table = renderDT({
    datatable(
      parent_df,
      rownames = FALSE,
      callback = callback_js,
      options = list(
        columnDefs = list(
          list(
            targets = 0,
            className = 'details-control',
            orderable = FALSE,
            render = JS("function(data, type, row, meta) {",
                        "  return '<span style=\"cursor:pointer;\">➕ ' + data + '</span>';",
                        "}")
          ),
          list(targets = 1, visible = FALSE) # 隐藏存储子数据的列
        ),
        ordering = FALSE, # 可按需删除开启排序
        paging = FALSE, # 可按需删除开启分页
        searching = FALSE # 可按需删除开启搜索
      )
    )
  }, server = FALSE)
}

shinyApp(ui, server)

自定义修改说明

  • 替换上述代码中df为你自己的数据集即可,父分组列名保持为parentID
  • 如果子列不是childID和childDesc,只需修改JS的format函数中对应的列名和表头文本即可,无需改动其他逻辑
  • 默认关闭了排序、分页、搜索功能,如需要删除options中对应的配置项即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:15:03