如何从上下文菜单中获取 TreeView 中当前选定的项目?

问题描述 投票:0回答:3

我需要将上下文菜单添加到我的

TreeWiew
。我设法用这个
mui.com's Menu
做到这一点,但我不知道如何在用户右键单击打开上下文菜单的树中获取所选项目。例如,假设用户打开上下文菜单并单击“复制消息”,我想知道用户选择了哪个节点(日历、OSS、index.js 等)并执行正确的操作。我尝试在 TreeView 中查找类似
onNodeSelect
的内容,但是当您打开该项目上的上下文菜单时它不会触发。 目前代码如下所示:

export default function FileSystemNavigator() {
  const [contextMenu, setContextMenu] = React.useState<{
    mouseX: number;
    mouseY: number;
  } | null>(null);

  const handleContextMenu = (event: React.MouseEvent) => {
    event.preventDefault();
    setContextMenu(
      contextMenu === null
        ? {
            mouseX: event.clientX + 2,
            mouseY: event.clientY - 6
          }
        : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu
          // Other native context menus might behave different.
          // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus.
          null
    );
  };

  const handleClose = () => {
    setContextMenu(null);
  };

  return (
    <div onContextMenu={handleContextMenu} style={{ cursor: "context-menu" }}>
      <TreeView
        aria-label="file system navigator"
        defaultCollapseIcon={<ExpandMoreIcon />}
        defaultExpandIcon={<ChevronRightIcon />}
        sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
      >
        <TreeItem nodeId="1" label="Applications">
          <TreeItem nodeId="2" label="Calendar" />
        </TreeItem>
        <TreeItem nodeId="5" label="Documents">
          <TreeItem nodeId="10" label="OSS" />
          <TreeItem nodeId="6" label="MUI">
            <TreeItem nodeId="8" label="index.js" />
          </TreeItem>
        </TreeItem>
      </TreeView>
      <Menu
        open={contextMenu !== null}
        onClose={handleClose}
        anchorReference="anchorPosition"
        anchorPosition={
          contextMenu !== null
            ? { top: contextMenu.mouseY, left: contextMenu.mouseX }
            : undefined
        }
      >
        <MenuItem onClick={handleClose}>Copy Ctrl+C</MenuItem>
        <MenuItem onClick={handleClose}>Delete</MenuItem>
        <MenuItem onClick={handleClose}>Move</MenuItem>
        <MenuItem onClick={handleClose}>Email</MenuItem>
      </Menu>
    </div>
  );
}

Here's
实时代码示例

reactjs material-ui electron treeview contextmenu
3个回答
3
投票

您可以通过一个小技巧来实现这一点 - 在打开上下文菜单时触发

click event
。这将触发
onNodeSelect
组件的
TreeView
回调。

export default function FileSystemNavigator() {
  // ...

  const [selectedNodeId, setSelectedNodeId] = React.useState<string | null>(
    null
  );

  const handleContextMenu = (event: React.MouseEvent) => {
    event.target.click();

    event.preventDefault();
    // ...
  };

  const handleNodeSelect = (event, nodeId) => {
    setSelectedNodeId(nodeId);
  };

  return (
    <div onContextMenu={handleContextMenu} style={{ cursor: "context-menu" }}>
      <TreeView
        {/* ... */}
        onNodeSelect={handleNodeSelect}
      ></TreeView>
      <Menu>
        {/* ... */}
        <MenuItem onClick={handleClose}>Delete node {selectedNodeId}</MenuItem>
        {/* ... */}
      </Menu>
    </div>
  );
}

它将产生以下结果:


1
投票

由于您只有一个上下文菜单,它根据右键单击发生的位置动态计算位置,因此您应该使用

onContextMenu
处理程序中的事件来查找右键单击的树项。 例如,当您右键单击“应用程序”节点时,在
event.target
handleContextMenu 
内,您会发现
<div class="MuiTreeItem-label">Applications</div>
- 您只需将这条信息存储在内部状态中,然后重复使用同一条信息MenuItem 单击处理程序内的状态。我假设您可以附加一些自定义属性,或者可能将 id 附加到 TreeItem,这样您就可以另外简化单击的树项的解析器(以避免检查 HTML div 的内部文本)。


0
投票

接受的解决方案对我来说并没有达到预期的效果。已经2岁了...

我所做的是创建一个 CustomTreeItem:请参阅此处,了解 CustomTreeItem 的一个很好的示例:

您可以用

<div onContextMenu={}></div>

包装您的 CustomTreeItem

以下是与包装器链接的 MUI 示例:

const CustomTreeItem = React.forwardRef(function CustomTreeItem(
  { id, itemId, label, disabled, children, ...other },
  ref,
) {
  const {
    getRootProps,
    getContentProps,
    getIconContainerProps,
    getCheckboxProps,
    getLabelProps,
    getGroupTransitionProps,
    getDragAndDropOverlayProps,
    status,
    publicAPI,
  } = useTreeItem2({ id, itemId, children, label, disabled, rootRef: ref });

// Rest of component...

    <div
      onContextMenu={(event) => {
        event.preventDefault();
        event.stopPropagation();
        console.log(itemId);
      }}
    >
      <TreeItem2Provider itemId={itemId}>
        <StyledTreeItemRoot {...getRootProps(other)}>
          <CustomTreeItemContent
            {...getContentProps({
              className: clsx("content", {
                "Mui-expanded": status.expanded,
                "Mui-selected": status.selected,
                "Mui-focused": status.focused,
                "Mui-disabled": status.disabled,
              }),
            })}
          >
            <TreeItem2IconContainer {...getIconContainerProps()}>
              <TreeItem2Icon status={status} />
            </TreeItem2IconContainer>
            <TreeItem2Checkbox {...getCheckboxProps()} />
            <CustomLabel
              {...getLabelProps({
                icon,
                expandable: expandable && status.expanded,
              })}
            />
            <TreeItem2DragAndDropOverlay {...getDragAndDropOverlayProps()} />
          </CustomTreeItemContent>
          {children && <TransitionComponent {...getGroupTransitionProps()} />}
        </StyledTreeItemRoot>
      </TreeItem2Provider>
    </div>

现在我们可以打开自定义菜单并围绕该特定项目执行操作。

© www.soinside.com 2019 - 2024. All rights reserved.