使用React JS实现右键菜单

36

我想知道在React组件中设置右键菜单的最佳实践/正确方法是否存在。

目前我有这个...

// nw is nw.gui from Node-Webkit
componentWillMount: function() {
    var menu = new nw.Menu();
    menu .append(new nw.MenuItem({
        label: 'doSomething',
        click: function() {
            // doSomething
        }
    }));

    // I'd like to know if this bit can be done in a cleaner/more succinct way...
    // BEGIN
    var that = this;
    addEventListener('contextmenu', function(e){
        e.preventDefault();
        // Use the attributes property to uniquely identify this react component 
        // (so different elements can have different right click menus)
        if (e.target.attributes[0].nodeValue == that.getDOMNode().attributes[0].nodeValue) {
            menu.popup(e.x, e.y);
        }
    })
    // END
},

这个可以用,但感觉有点凌乱,想知道是否有其他方法可用,非常感谢任何提供信息的人!

谢谢!


2
看一下这篇文章,我认为它会对你有所帮助。 - pablolmiranda
@pablolmiranda 哦,好的,谢谢。我之前没看过这篇文章。我找到了这个视频(https://www.youtube.com/watch?v=ecc0JopiZe4),它有关于node-webkit的信息,但没有React相关的内容。我不知道是否有更好的方法。我想我可以使用唯一的ID和DIV来引用这个项目,这可能会更清晰一些,但我不确定。还是谢谢! - Tom
3个回答

55

更新:

我找到了解决方法 - 这是你可以做的事情

var addMenu;

componentWillMount: function() {
    addMenu = new nw.Menu();
    addMenu.append(new nw.MenuItem({
        label: 'doSomething',
        click: function() {
            // doSomething
        }
    }));
},

contextMenu: function(e) {
    e.preventDefault();
    addMenu.popup(e.clientX, e.clientY);
},

render: function(){
    return <button onClick={this.handleClick} onContextMenu={this.contextMenu}>SomethingUseful</button>
}

在渲染时,你可以为这个React组件的右键单击事件(onContextMenu)传递一个函数。


2
请问您能否添加JSFiddle示例? - Peter
2
嗨 - 这里有一些可能有用的东西 - (https://jsfiddle.net/q09xkja9/3/) 我正在使用的右键菜单(addMenu = new nw.Menu())来自Node-Webkit,它提供了对本地菜单的访问。希望这个例子能给你一个想法! - Tom
1
@Tom 这个 JSFiddle 应该是能够工作的吗?我所看到的只有一个白色的区域,应该出现输出/点击事件。 - kojow7
@kojow7,恐怕我已经很久没有看过这个了,我不知道我在2015年尝试的东西是否仍然有效。抱歉帮不上更多忙! - Tom
1
@kojow7 这里有一个更新的代码片段:https://jsfiddle.net/ejtkn8x1/(不得不将“语言”设置从“使用jQuery”切换到“带JSX的Babel”) - 1j01

16

在处理弹出菜单时需要注意以下几点:

  1. 应该将其渲染在其父元素和同级元素之外,最好是在覆盖整个文档的叠加层中的最后一个子元素中。
  2. 特殊的逻辑应该确保它始终显示在屏幕上,永远不会被屏幕边缘裁剪。
  3. 如果涉及到层次结构,子弹出菜单应该与前一个弹出菜单中的项目(触发器)对齐。

我创建了一个可以用来实现所有这些功能的库:

http://dkozar.github.io/react-data-menu/


6

我在使用Material UI时也在寻找解决方案。你需要做的第一步是禁用浏览器右键默认行为,然后添加你想要的菜单,下面是可工作的代码:

import React from 'react';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import InboxIcon from '@material-ui/icons/MoveToInbox';
import DraftsIcon from '@material-ui/icons/Drafts';
import SendIcon from '@material-ui/icons/Send';

const StyledMenu = withStyles({
  paper: {
    border: '1px solid #d3d4d5',
  },
})((props) => (
  <Menu
    elevation={0}
    getContentAnchorEl={null}
    anchorOrigin={{
      vertical: 'bottom',
      horizontal: 'center',
    }}
    transformOrigin={{
      vertical: 'top',
      horizontal: 'center',
    }}
    {...props}
  />
));

const StyledMenuItem = withStyles((theme) => ({
  root: {
    '&:focus': {
      backgroundColor: theme.palette.primary.main,
      '& .MuiListItemIcon-root, & .MuiListItemText-primary': {
        color: theme.palette.common.white,
      },
    },
  },
}))(MenuItem);

export default function CustomizedMenus() {
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handleClick = (event) => {
    event.preventDefault();
    setAnchorEl(event.currentTarget);
  };

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

  return (
    <div>
      <Button
        aria-controls="customized-menu"
        aria-haspopup="true"
        variant="contained"
        color="primary"
        onContextMenu={handleClick}
      >
        Open Menu
      </Button>
      <StyledMenu
        id="customized-menu"
        anchorEl={anchorEl}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleClose}
      >
        <StyledMenuItem>
          <ListItemIcon>
            <SendIcon fontSize="small" />
          </ListItemIcon>
          <ListItemText primary="Sent mail" />
        </StyledMenuItem>
        <StyledMenuItem>
          <ListItemIcon>
            <DraftsIcon fontSize="small" />
          </ListItemIcon>
          <ListItemText primary="Drafts" />
        </StyledMenuItem>
        <StyledMenuItem>
          <ListItemIcon>
            <InboxIcon fontSize="small" />
          </ListItemIcon>
          <ListItemText primary="Inbox" />
        </StyledMenuItem>
      </StyledMenu>
    </div>
  );
}

以及沙盒项目


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接