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

如何在R Shiny与shinyjqui中动态创建并保存用户自定义拖拽组合

实现Shiny拖拽应用的自定义组合保存与动态按钮生成

核心实现思路

  • 通过shinyjqui的拖拽组件监听用户操作,获取拖拽到目标容器的元素组合
  • 用reactiveValues动态存储自定义组合,替代硬编码的vec_suggestion1
  • 根据存储的组合数量,自动生成对应的调用按钮,点击按钮可将对应组合加载到目标容器

完整代码示例

library(shiny)
library(shinyjqui)

ui <- fluidPage(
  # 可拖拽元素区域
  div(
    style = "margin: 20px; padding: 10px; border: 1px solid #ccc;",
    h4("可拖拽元素"),
    div(id = "drag_A", class = "drag-item", style = "display: inline-block; padding: 8px 15px; background: #e0f7fa; margin: 5px;", "A"),
    div(id = "drag_B", class = "drag-item", style = "display: inline-block; padding: 8px 15px; background: #ffebee; margin: 5px;", "B")
  ),
  
  # 目标拖拽容器
  div(
    style = "margin: 20px; padding: 20px; border: 2px dashed #2196f3; min-height: 100px;",
    h4("拖拽目标容器"),
    div(id = "droppable_cell", class = "droppable-container")
  ),
  
  # 保存组合按钮
  actionButton("save_combo", "保存当前组合"),
  
  # 动态生成的组合调用按钮区域
  div(id = "combo_buttons", style = "margin: 20px;")
)

server <- function(input, output, session) {
  # 初始化响应式变量存储自定义组合
  rv <- reactiveValues(
    suggestions = list(
      vec_suggestion1 = c("A", "B")  # 保留原硬编码组合
    )
  )
  
  # 初始化拖拽组件
  observe({
    # 标记可拖拽元素
    jqui_draggable(".drag-item", options = list(helper = "clone"))
    
    # 标记目标容器,监听drop事件
    jqui_droppable("#droppable_cell", options = list(
      accept = ".drag-item",
      drop = JS("function(event, ui) {
                  // 克隆拖拽元素并添加到目标容器
                  $(ui.helper).clone().appendTo(this);
                }")
    ))
  })
  
  # 保存当前组合到reactiveValues
  observeEvent(input$save_combo, {
    # 触发前端获取容器内元素
    session$sendCustomMessage(type = "get_items", message = list(selector = "#droppable_cell .drag-item"))
    
    # 等待前端返回的元素列表
    req(input$current_items)
    
    # 生成新的组合名称(vec_suggestion2、vec_suggestion3...)
    new_combo_name <- paste0("vec_suggestion", length(rv$suggestions) + 1)
    rv$suggestions[[new_combo_name]] <- input$current_items
    
    # 清空目标容器
    session$sendCustomMessage(type = "clear_container", message = list(selector = "#droppable_cell"))
  })
  
  # 动态生成组合调用按钮
  output$combo_buttons <- renderUI({
    button_list <- lapply(names(rv$suggestions), function(combo_name) {
      actionButton(
        inputId = paste0("btn_", gsub("vec_", "", combo_name)),
        label = paste("加载", combo_name),
        onclick = paste0("Shiny.setInputValue('load_combo', '", combo_name, "');")
      )
    })
    do.call(tagList, button_list)
  })
  
  # 加载选中的组合到目标容器
  observeEvent(input$load_combo, {
    target_combo <- rv$suggestions[[input$load_combo]]
    req(target_combo)
    
    # 清空目标容器后添加组合元素
    session$sendCustomMessage(type = "clear_container", message = list(selector = "#droppable_cell"))
    lapply(target_combo, function(item) {
      session$sendCustomMessage(
        type = "add_item",
        message = list(selector = "#droppable_cell", item_text = item)
      )
    })
  })
  
  # 前端JS工具函数
  tags$head(tags$script(HTML("
    // 获取容器内元素文本并传递给后端
    Shiny.addCustomMessageHandler('get_items', function(message) {
      var items = $(message.selector).map(function() {
        return $(this).text();
      }).get();
      Shiny.setInputValue('current_items', items);
    });
    
    // 清空目标容器
    Shiny.addCustomMessageHandler('clear_container', function(message) {
      $(message.selector).empty();
    });
    
    // 向容器添加指定元素
    Shiny.addCustomMessageHandler('add_item', function(message) {
      var bgColor = message.item_text === 'A' ? '#e0f7fa' : '#ffebee';
      $('<div>').addClass('drag-item').css({
        'display': 'inline-block',
        'padding': '8px 15px',
        'background': bgColor,
        'margin': '5px'
      }).text(message.item_text).appendTo(message.selector);
    });
  ")))
}

shinyApp(ui, server)

关键逻辑说明

  1. 拖拽交互与元素获取:

    • 用jqui_draggable和jqui_droppable实现基础拖拽克隆功能
    • 自定义JS消息处理器get_items提取目标容器内的元素文本,传递给Shiny后端
  2. 动态组合存储:

    • 用reactiveValues$suggestions列表统一存储所有组合,包含初始硬编码的vec_suggestion1
    • 点击保存按钮时,自动按序号生成新组合名称并追加到列表
  3. 动态按钮生成与组合加载:

    • 通过renderUI遍历组合列表,为每个组合生成btn_suggestionN格式的按钮
    • 点击按钮触发load_combo输入,后端取出对应组合,通过JS将元素添加到目标容器

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:09:52