在模式内容内部单击时,模式已关闭

时间:2018-10-12 09:10:38

标签: javascript reactjs

我正在尝试使用reactjs创建一个可定制的通用可扩展模式。我知道这里有很多图书馆,但是我只是为了理解反应生态系统而发展。但是,在我的模态中,当我在模态内容中单击时,模态会关闭。仅当单击关闭按钮且位于模态区域之外时,模态才应关闭。

这就是我所做的。演示也在那里

https://codepen.io/anon/pen/mzMdoq

代码

class Portal extends React.Component {
  render() {
    return ReactDOM.createPortal(
      <div
        style={{
          position: "absolute",
          top: "0",
          bottom: "0",
          left: "0",
          right: "0",
          display: "grid",
          justifyContent: "center",
          alignItems: "center",
          backgroundColor: "rgba(0,0,0,0.3)"
        }}
        onClick={this.props.onClose}
      >
        <div
          style={{
            padding: 20,
            background: "#fff",
            borderRadius: "2px",
            display: "inline-block",
            minHeight: "300px",
            margin: "1rem",
            position: "relative",
            minWidth: "300px",
            boxShadow: "0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)",
            justifySelf: "center"
          }}
        >
          {this.props.children}
          <hr />
          <button onClick={this.props.onClose}>Close</button>
        </div>
      </div>,
      document.body
    );
  }
}

class Modal extends React.Component {
  modalRef = React.createRef();
  componentDidMount() {
    document.addEventListener("mousedown", this.handleClick, false);
  }
  componentWillUnmount() {
    document.removeEventListener("mousedown", this.handleClick, false);
  }
  handleClick = e => {
    const node = this.modalRef.current;
    console.log("props", node);
    if (
      this.modalRef &&
      this.modalRef.current &&
      this.modalRef.current.contains(e.target)
    ) {
      return;
    } else {
      this.props.onClose();
    }
  };
  render() {
    return (
      <React.Fragment>
        <Portal {...this.props} ref={this.modalRef} />
      </React.Fragment>
    );
  }
}

class ModalExample extends React.Component {
  state = { showModal: false };
  showModal = () => this.setState({ showModal: true });
  handleClose = () => this.setState({ showModal: false });
  render() {
    const { showModal } = this.state;
    return (
      <React.Fragment>
        <button onClick={this.showModal}>Modal</button>
        {showModal ? (
          <Modal showModal={showModal} onClose={this.handleClose}>
            This is the modal content!
          </Modal>
        ) : null}
      </React.Fragment>
    );
  }
}

function App() {
  return (
    <div className="App">
      <h1>Hello</h1>
      <ModalExample />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

4 个答案:

答案 0 :(得分:0)

您应该删除onClick={this.props.onClose}内的ReactDOM.createPortal,它将正常工作

答案 1 :(得分:0)

将e.stopPropagation()添加到模态主体的onClick。像这样

<div
  style={{
    padding: 20,
    background: "#fff",
    borderRadius: "2px",
    display: "inline-block",
    minHeight: "300px",
    margin: "1rem",
    position: "relative",
    minWidth: "300px",
    boxShadow: "0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)",
    justifySelf: "center"
  }}
  onClick={e => e.stopPropagation()}
>
  {this.props.children}
  <hr />
  <button onClick={this.props.onClose}>Close</button>
</div>

答案 2 :(得分:0)

嗯,这不完全是一个答案,但是如果有帮助的话……

我通常以这种方式生成模态

https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_modal

在这里,您可以看到DOM中已经存在模态,并且使用js可以根据需要将其隐藏或显示。 div已存在,因此与您的有所不同。

答案 3 :(得分:0)

您的覆盖div包装了模式内容div,因此,点击内容也被视为点击了覆盖。

解决此问题的一种方法是不将模式内容嵌套在叠加层中,而是将其移动到外部:

return ReactDOM.createPortal(
      <div style={{
          position: "absolute",
          top: "0",
          bottom: "0",
          left: "0",
          right: "0",
          display: "grid",
          justifyContent: "center",
          alignItems: "center"
        }}>
      <div
        style={{
          position: "absolute",
          top: "0",
          bottom: "0",
          left: "0",
          right: "0",
          display: "grid",
          justifyContent: "center",
          alignItems: "center",
          backgroundColor: "rgba(0,0,0,0.3)"
        }} onClick={this.props.onClose}
      />
        <div
          style={{
            padding: 20,
            background: "#fff",
            borderRadius: "2px",
            display: "inline-block",
            minHeight: "300px",
            margin: "1rem",
            position: "relative",
            minWidth: "300px",
            boxShadow: "0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)",
            justifySelf: "center"
          }}
        >
          {this.props.children}
          <hr />
          <button onClick={this.props.onClose}>Close</button>
        </div>
      </div>,
      document.body
    );