如何在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)
关键逻辑说明
拖拽交互与元素获取:
- 用
jqui_draggable和jqui_droppable实现基础拖拽克隆功能 - 自定义JS消息处理器
get_items提取目标容器内的元素文本,传递给Shiny后端
- 用
动态组合存储:
- 用
reactiveValues$suggestions列表统一存储所有组合,包含初始硬编码的vec_suggestion1 - 点击保存按钮时,自动按序号生成新组合名称并追加到列表
- 用
动态按钮生成与组合加载:
- 通过
renderUI遍历组合列表,为每个组合生成btn_suggestionN格式的按钮 - 点击按钮触发
load_combo输入,后端取出对应组合,通过JS将元素添加到目标容器
- 通过
内容的提问来源于stack exchange,提问作者TarJae
相关产品推荐
相关产品推荐

