如何添加右键菜单以反应表行并访问其属性?

问题描述 投票:1回答:1

我已经在我的项目中添加了react-table包,一切都很好,但是我也希望能够右键单击一行并对其执行一些操作(取消,暂停等)。我正在将React与Typescript一起使用,但我希望它不会增加任何复杂性。

我最初的想法是使用react-contextify,但是我找不到任何可以将react-table和react-contextify结合在一起的工作示例。

我发现的唯一“工作”示例就是这个例子:React Context Menu on react table using react-contexify

我最终没有使用react-contextify,它“很不错”,但是我对此并不完全确定,因为有时我会不断收到类似的异常:

Uncaught TypeError: Cannot read property 'original' of undefined

我现在拥有的代码是:

const columns = [
      {
        Header: "Name",
        accessor: "name"
      },
      {
        Header: "Age",
        accessor: "age",
        Cell: (props: { value: React.ReactNode }) => (
          <span className="number">{props.value}</span>
        ) 
      },
      {
        id: "friendName", // Required because our accessor is not a string
        Header: "Friend Name",
        accessor: (d: { friend: { name: any } }) => d.friend.name // Custom value accessors!
      },
      {
        Header: (props: any) => <span>Friend Age</span>, // Custom header components!
        accessor: "friend.age"
      }
    ];

return (
      <div>
        <ContextMenuTrigger id="menu_id">
          <ReactTable
            data={data}
            columns={columns}
            showPagination={false}
            getTdProps={(
              state: any,
              rowInfo: any,
              column: any,
              instance: any
            ) => {
              return {
                onClick: (e: any, handleOriginal: any) => {
                  const activeItem = rowInfo.original;
                  console.log(activeItem);
                },
                onContextMenu: () => {
                  console.log("contextMenu", rowInfo);
                  this.setState({
                    showContextMenu: true,
                    rowClickedData: rowInfo.original
                  });
                }
              };
            }}
          />
        </ContextMenuTrigger>
        {this.state.showContextMenu ? (
          <MyAwesomeMenu clickedData={this.state.rowClickedData} />
        ) : null}
      </div>
    );
  }
}
const MyAwesomeMenu = (props: { clickedData: any }) => (
  <ContextMenu id="menu_id">
    <MenuItem
      data={props.clickedData}
      onClick={(e, props) => onClick({ e, props })}
    >
      <div className="green">ContextMenu Item 1 - {props.clickedData.id}</div>
    </MenuItem>
  </ContextMenu>
);
const onClick = (props: {
  e:
    | React.TouchEvent<HTMLDivElement>
    | React.MouseEvent<HTMLDivElement, MouseEvent>;
  props: Object;
}) => console.log("-------------->", props);

将上下文菜单添加到react-table以便我可以使用单击的行的道具的最佳(也是最简单的方法是什么?我真的很喜欢react-contextify,但是还没有找到任何例子。

谢谢

reactjs typescript contextmenu react-table
1个回答
0
投票

React Hooks exmaple on dev.to

基于类的组件示例on codepen

class App extends React.Component {
  constructor() {
    super();

    this.state = {
      value: ''
    };
  }

  render() {
    return(
      <div>
        {
          ['row1', 'row2', 'row3'].map((row) => {
            return (
              <ContextMenu
                key={row}
                buttons={[
                  { label: 'Editovat', onClick: (e) => alert(`Editace ${row}`) },
                  { label: 'Smazat', onClick: (e) => alert(`Mažu ${row}`) }
                ]}
              >
                <div className="row">{row}</div>
              </ContextMenu>
            );
          })
        }
      </div>
    );
  }
}

class ContextMenu extends React.Component {
  static defaultProps = {
    buttons: []
  };

  constructor() {
    super();

    this.state = {
      open: false
    };
  }

  componentDidMount() {
    document.addEventListener('click', this.handleClickOutside);
    document.addEventListener('contextmenu', this.handleRightClickOutside);
  }

  handleClickOutside = (e) => { 
    if (!this.state.open) {
      return;
    }

    const root = ReactDOM.findDOMNode(this.div);
    const context = ReactDOM.findDOMNode(this.context);
    const isInRow = (!root.contains(e.target) || root.contains(e.target));
    const isInContext = !context.contains(e.target);

    if (isInRow && isInContext) {
      this.setState({
        open: false
      });
    } 
  }

  handleRightClickOutside = (e) => {
    if (!this.state.open) {
      return;
    }

    const root = ReactDOM.findDOMNode(this.div);
    const isInRow = !root.contains(e.target);

    if (isInRow) {
      this.setState({
        open: false
      });
    }
  }

  handleRightClick = (e) => {
    e.preventDefault();
  console.log(e.nativeEvent, window.scrollY);
    this.setState({
      open: true,
      top: window.scrollY + e.nativeEvent.clientY,
      left: e.nativeEvent.clientX,
    });
  }

  render() {
    return (
      <div
        onContextMenu={this.handleRightClick}
        ref={(node) => this.div = node}
      >
        {this.props.children}

        {
          !this.state.open
          ? null
          : <div
              className="context"
              ref={(div) => this.context = div}
              style={{ top: this.state.top, left: this.state.left }}
          >
              <ul>
                {
                  // button - name, onClick, label
                  this.props.buttons.length > 0 &&
                  this.props.buttons.map((button) => {
                    return <li key={button.label}>
                      <a href="#" onClick={button.onClick}>
                        {button.label}
                      </a>
                    </li>
                  })
                }
              </ul>
          </div>
        }
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
© www.soinside.com 2019 - 2024. All rights reserved.