如何在Shiny的jsTreeR菜单列表项添加悬停文本弹窗?
实现jsTreeR菜单项悬停弹窗的方案
可以实现这个需求,核心思路是给Menu区域的可拖拽节点添加自定义tooltip数据,通过jQuery监听鼠标悬停事件来显示弹窗,同时确保复制到目标区域的节点不会保留该功能。具体实现如下:
1. 给可拖拽节点添加tooltip说明数据
在定义nodes时,为每个moveable类型的节点添加data属性,存储对应的悬停说明文本:
list(text = "Dog", type = "moveable", state = list(disabled = TRUE), data = list(tooltip = "一种常见的家养宠物,忠诚活泼")), list(text = "Cat", type = "moveable", state = list(disabled = TRUE), data = list(tooltip = "温顺独立的家养宠物,喜欢独处"))
2. 添加tooltip样式与交互逻辑
在原有的JS脚本中新增tooltip的创建、悬停监听逻辑,同时在节点复制后清除目标节点的tooltip相关属性:
- 创建全局tooltip元素,默认隐藏
- 仅对Menu区域内的
moveable节点触发悬停弹窗 - 复制节点到目标区域后,移除该节点的tooltip关联数据,避免弹窗继续生效
完整修改后的代码
library(jsTreeR) library(shiny) nodes <- list( list( text = "Menu", state = list(opened = TRUE), children = list( list(text = "Dog", type = "moveable", state = list(disabled = TRUE), data = list(tooltip = "一种常见的家养宠物,忠诚活泼")), list(text = "Cat", type = "moveable", state = list(disabled = TRUE), data = list(tooltip = "温顺独立的家养宠物,喜欢独处")) ) ), list(text = ">>> Drag here <<<", type = "target", state = list(opened = TRUE)) ) dnd <- list( always_copy = TRUE, inside_pos = "last", is_draggable = JS( "function(node) {", " return node[0].type === 'moveable';", "}" ) ) mytree <- jstree( nodes, dragAndDrop = TRUE, dnd = dnd, types = list(moveable = list(), target = list()) ) script <- ' $(document).ready(function(){ // 创建tooltip元素并添加到页面 $("body").append("<div id=\"jstree-tooltip\" style=\"position:absolute; background:#333; color:white; padding:5px 10px; border-radius:4px; display:none; z-index:9999;\"></div>"); var tooltip = $("#jstree-tooltip"); // 监听Menu下moveable节点的鼠标进入事件 $("#mytree").on("mouseenter", ".jstree-node[data-jstree-type=\"moveable\"]", function(e){ // 仅Menu父节点下的触发tooltip if($(this).closest(".jstree-node").find(".jstree-anchor:contains(Menu)").length > 0){ var tooltipText = $(this).data("jstree").data.tooltip; tooltip.text(tooltipText).show(); // 定位到鼠标位置附近 tooltip.css({ top: e.pageY + 10 + "px", left: e.pageX + 10 + "px" }); } }); // 鼠标离开时隐藏tooltip $("#mytree").on("mouseleave", ".jstree-node[data-jstree-type=\"moveable\"]", function(){ tooltip.hide(); }); // 鼠标移动时更新tooltip位置 $("#mytree").on("mousemove", ".jstree-node[data-jstree-type=\"moveable\"]", function(e){ if(tooltip.is(":visible")){ tooltip.css({ top: e.pageY + 10 + "px", left: e.pageX + 10 + "px" }); } }); var LETTERS = ["A", "B", "C"]; var Visited = {}; $("#mytree").on("copy_node.jstree", function(e, data){ var oldid = data.original.id; var visited = Object.keys(Visited); if(visited.indexOf(oldid) === -1){ Visited[oldid] = 0; }else{ Visited[oldid]++; } var letter = LETTERS[Visited[oldid]]; var node = data.node; var id = node.id; var index = $("#"+id).index() + 1; var text = index + ". " + node.text + " " + letter; Shiny.setInputValue("choice", text); var instance = data.new_instance; instance.rename_node(node, text); // 移除复制后节点的tooltip相关属性 $("#" + id).removeData("jstree").removeAttr("data-jstree"); }); }); ' ui <- fluidPage( tags$head(tags$script(HTML(script))), fluidRow(jstreeOutput("mytree")) ) server <- function(input, output, session){ output[["mytree"]] <- renderJstree(mytree) } shinyApp(ui, server)
关键细节说明
- tooltip样式:设置深色背景、白色文字和高层级z-index,确保弹窗清晰且不被遮挡
- 节点范围控制:通过父节点包含"Menu"文本的判断,仅原始Menu区域的节点触发弹窗
- 复制后清理:在节点复制完成后,移除目标节点的
data-jstree属性,彻底清除tooltip关联数据
内容的提问来源于stack exchange,提问作者Village.Idyot
相关产品推荐
相关产品推荐

