通过actionButton触发observeEvent实现shinyjqui指定向量拖拽至表格
解决方案
要实现点击按钮将指定元素批量放置到网格的特定位置,并同步移除原区域的元素,可通过以下步骤修改代码:
1. 调整UI,添加触发按钮
在UI中新增一个actionButton,用于触发元素放置操作,同时添加自定义JS函数处理元素移动逻辑:
ui <- fluidPage( tags$head(tags$script( JS( " $(function() { $('[id^=droppable_cell]').sortable({ connectWith: '#letters', drop: function(event, ui) { $(this).append(ui.draggable); } }) }); // 全局函数:将指定元素移动到目标单元格 window.moveElementToCell = function(elementId, targetCellId) { var $element = $('#' + elementId); var $target = $('#' + targetCellId); $target.append($element); // 刷新排序组件状态,保证后续拖拽功能正常 $('#letters').sortable('refresh'); $('[id^=droppable_cell]').sortable('refresh'); } " ) ), tags$style(HTML("...")), # 保留原样式代码 # 添加触发按钮 actionButton("place_elements", "放置指定元素"), div(class = "table-container", ...) # 保留原网格和orderInput代码 )
2. 服务器端逻辑处理
在server函数中监听按钮点击事件,定义要放置的元素和对应目标单元格,调用JS函数完成移动,并更新原区域的元素列表:
server <- function(input, output, session) { observeEvent(input$place_elements, { # 定义要放置的元素向量和对应目标单元格 vec <- c("A", "B", "C") target_cells <- paste0("droppable_cell_", 1:3) # 对应第1-3个网格单元格 # 遍历元素,逐个调用JS函数完成移动 for(i in seq_along(vec)) { element_id <- paste0("letters_", vec[i]) # orderInput生成的元素ID格式为"[inputId]_[item]" runjs(sprintf("moveElementToCell('%s', '%s')", element_id, target_cells[i])) } # 更新letters区域,移除已放置的元素 remaining_items <- setdiff(LETTERS[1:7], vec) updateOrderInput(session, "letters", items = remaining_items) }) }
3. 完整代码
整合后的完整可运行代码如下:
library(shiny) library(shinyjqui) connections <- paste0("droppable_cell_", 1:7) # 网格单元格ID ui <- fluidPage( tags$head(tags$script( JS( " $(function() { $('[id^=droppable_cell]').sortable({ connectWith: '#letters', drop: function(event, ui) { $(this).append(ui.draggable); } }) }); // 全局函数:将指定元素移动到目标单元格 window.moveElementToCell = function(elementId, targetCellId) { var $element = $('#' + elementId); var $target = $('#' + targetCellId); $target.append($element); // 刷新排序组件状态,保证后续拖拽功能正常 $('#letters').sortable('refresh'); $('[id^=droppable_cell]').sortable('refresh'); } " ) ), # 样式代码 tags$style( HTML( " .grid-table { width: 150px; border-collapse: collapse; } .grid-cell { width: 100%; height: 50px; border: 1px solid black; background-color: white; text-align: center; margin: 0; padding: 5px; } .grid-cell-text { display: flex; align-items: center; justify-content: center; height: 100%; background-color: steelblue; color: white; font-size: 18px; } .droppable-cell { background-color: lightgray; } .table-container { display: flex; position: absolute; left: 550px; top: 30px; margin-top: 0px; overflow: hidden; } " ) )), # 触发按钮 actionButton("place_elements", "放置指定元素"), div( class = "table-container", div( class = "grid-table", id = "my_grid", div( class = "grid-row", div(class = "grid-cell grid-cell-text", "my_grid"), div(id = "droppable_cell_1", class = "grid-cell droppable-cell", ""), div(id = "droppable_cell_2", class = "grid-cell droppable-cell", ""), div(id = "droppable_cell_3", class = "grid-cell droppable-cell", ""), div(id = "droppable_cell_4", class = "grid-cell droppable-cell", ""), div(id = "droppable_cell_5", class = "grid-cell droppable-cell", ""), div(id = "droppable_cell_6", class = "grid-cell droppable-cell", ""), div(id = "droppable_cell_7", class = "grid-cell droppable-cell", "") ) ), orderInput('letters', 'Letters', items = LETTERS[1:7], connect = connections) ) ) server <- function(input, output, session) { observeEvent(input$place_elements, { # 定义要放置的元素和对应目标单元格 vec <- c("A", "B", "C") target_cells <- paste0("droppable_cell_", 1:3) # 逐个移动元素到目标单元格 for(i in seq_along(vec)) { element_id <- paste0("letters_", vec[i]) runjs(sprintf("moveElementToCell('%s', '%s')", element_id, target_cells[i])) } # 更新letters区域,移除已放置的元素 remaining_items <- setdiff(LETTERS[1:7], vec) updateOrderInput(session, "letters", items = remaining_items) }) } shinyApp(ui, server)
关键说明
orderInput生成的元素ID固定格式为[inputId]_[item],比如元素A的ID是letters_A,这是JS定位元素的核心依据- 自定义JS函数
moveElementToCell负责完成元素的DOM移动,并刷新排序组件状态,避免后续拖拽功能异常 - 使用
updateOrderInput同步更新原区域的元素列表,确保视觉和功能上的一致性
内容的提问来源于stack exchange,提问作者TarJae
相关产品推荐
相关产品推荐

