【问题标题】:Material UI TreeView unexpectedly toggles node when context menu item is clicked单击上下文菜单项时,Material UI TreeView 意外切换节点
【发布时间】:2022-10-17 03:11:35
【问题描述】:

我通过使用以下 .tsx 代码 (sandbox demo here) 为每个节点添加上下文菜单来扩展 material ui tree view demo

import * as React from "react";
import { Typography, Menu, MenuItem } from "@mui/material";
import TreeView from "@mui/lab/TreeView";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import TreeItem from "@mui/lab/TreeItem";

interface RenderTree {
  id: string;
  name: string;
  children?: readonly RenderTree[];
}

const data: RenderTree = {
  id: "root",
  name: "Parent",
  children: [
    {
      id: "1",
      name: "Child - 1"
    },
    {
      id: "3",
      name: "Child - 3",
      children: [
        {
          id: "4",
          name: "Child - 4"
        }
      ]
    }
  ]
};

const NodeWithContextMenu = (props) => {
  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" }}>
      <Typography>{props.label}</Typography>
      <Menu
        open={contextMenu !== null}
        onClose={handleClose}
        anchorReference="anchorPosition"
        anchorPosition={
          contextMenu !== null
            ? { top: contextMenu.mouseY, left: contextMenu.mouseX }
            : undefined
        }
      >
        <MenuItem onClick={handleClose}>Copy</MenuItem>
        <MenuItem onClick={handleClose}>Print</MenuItem>
        <MenuItem onClick={handleClose}>Highlight</MenuItem>
        <MenuItem onClick={handleClose}>Email</MenuItem>
      </Menu>
    </div>
  );
};

export default function RichObjectTreeView() {
  const renderTree = (nodes: RenderTree) => (
    <TreeItem
      key={nodes.id}
      nodeId={nodes.id}
      label={<NodeWithContextMenu label={nodes.name} />}
    >
      {Array.isArray(nodes.children)
        ? nodes.children.map((node) => renderTree(node))
        : null}
    </TreeItem>
  );

  return (
    <TreeView
      aria-label="rich object"
      defaultCollapseIcon={<ExpandMoreIcon />}
      defaultExpanded={["root"]}
      defaultExpandIcon={<ChevronRightIcon />}
      sx={{ height: 110, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
    >
      {renderTree(data)}
    </TreeView>
  );
}

在选择右键单击上下文菜单项时,底层树节点被切换(扩展或收缩)。当单击上下文菜单项或其他任何位置以关闭上下文菜单时,会发生这种情况。

预期行为:上下文菜单的使用应该不是切换底层节点。

这是基本 mui.com 演示的code sandbox 和上面我的code sample

【问题讨论】:

标签: javascript reactjs typescript material-ui treeview


【解决方案1】:

尝试仅通过单击图标进行扩展并阻止单击标签进行扩展时,我遇到了同样的问题。

这是一种解决方法。

您需要导入 TreeViewContext

防止标签点击被包装的 TreeItem 处理。

使用省略切换扩展逻辑的正常点击处理代码。

因此,在您的情况下,您需要自定义 contextMenu 事件处理程序...

function ExpandIconOnlyTreeItem(props:TreeItemProps){
  const {label,...other} = props;
  const context = useContext(TreeViewContext.default) as any;

  const focused = context.isFocused ? context.isFocused(props.nodeId) : false;
  const labelClicked = useCallback(
    (event:any) => {
      if (!focused) {
        context.focus(props.nodeId);
      }
  
      const multiple = context.multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey);
  
      
  
      if (!context.selectionDisabled) {
        if (multiple) {
          if (event.shiftKey) {
            context.selectRange(event, { end: props.nodeId });
          } else {
            context.selectNode(event, props.nodeId, true);
          }
        } else {
          context.selectNode(event, props.nodeId);
        }
      }
      event.stopPropagation()
      if (props.onClick) {
        props.onClick(event);
      }
    }
  ,[]);
  
  return <TreeItem {...other} label={<span onClick={labelClicked}>{label}</span>}/>
}

【讨论】:

    猜你喜欢
    • 2019-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多