reactjs 在外部单击时React关闭模态

mnowg1ta  于 2022-11-04  发布在  React
关注(0)|答案(9)|浏览(168)

我已经创建了一个基本的模态使用react没有任何库,它的工作完美,现在当我点击模态外,我想关闭模态。
这是CodeSandbox的实时预览
我索引.js:

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      showModal: false
    };
  }

  handleClick = () => {
    this.setState(prevState => ({
      showModal: !prevState.showModal
    }));
  };

  render() {
    return (
      <>
        <button onClick={this.handleClick}>Open Modal</button>
        {this.state.showModal && (
          <div className="modal">
            I'm a modal!
            <button onClick={() => this.handleClick()}>close modal</button>
          </div>
        )}
      </>
    );
  }
}

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

jslywgbw1#

实现此目的最简单的方法是在 Package 器中调用closeModal函数,并在实际模态中停止传播
比如说

<ModalWrapper onClick={closeModal} >
  <InnerModal onClick={e => e.stopPropagation()} /> 
</ModalWrapper>
tzdcorbm

tzdcorbm2#

如果使用ref,则会有点棘手
观看CodeSandBox

h6my8fg2

h6my8fg23#

你可以通过为模态背景创建一个div来实现它,它位于模态主体的旁边。使用绝对位置和100%的高度和宽度值使它覆盖整个屏幕。
这样,模态主体就位于背景之上。如果您单击模态主体,则不会发生任何事情,因为背景没有接收到单击事件。但如果您单击背景,则可以处理单击事件并关闭模态。
关键的是,模态背景不会包裹模态主体,而是位于它旁边。如果它包裹了主体,那么在背景或主体上的任何点击都会关闭模态。
第一个

f5emj3cl

f5emj3cl4#

有关工作示例,请参见随附的Codesandbox
你就快成功了。首先,你需要在你的handleClick()中做一个回调函数,将一个closeMenu方法添加到文档中:

handleClick = event => {
    event.preventDefault();

    this.setState({ showModal: true }, () => {
      document.addEventListener("click", this.closeMenu);
    });
  };

然后切换closeMenu()内的状态:

closeMenu = () => {
    this.setState({ menuOpen: false }, () => {
      document.removeEventListener('click', this.closeMenu);
    });
  }

任何时候你点击组件的外部,然后它会关闭它。:)

ulydmbyx

ulydmbyx5#

这对我很有效:
需要使用e.stopPropagation来防止循环

handleClick = e => {
 if (this.state.showModal) {
   this.closeModal();
   return;
 }
 this.setState({ showModal: true });
 e.stopPropagation();
 document.addEventListener("click", this.closeModal);
};

然后:

closeModal = () => {
 this.setState({ showModal: false });
 document.removeEventListener("click", this.closeModal);
};

希望会有所帮助

ubbxdtey

ubbxdtey6#

我是这样解决的:顺便说一句,我是一个初级开发人员,所以检查它,GL。
在index.html中:

<div id="root"></div>
<div id="modal-root"></div>

在index.js中:

ReactDOM.render(
  <React.StrictMode>
    <ModalBase />
  </React.StrictMode>,
  document.getElementById("modal-root")
);

在App.js中:

const [showModal, setShowModal] = useState(false);
 {showModal && (
  <ModalBase setShowModal={setShowModal}>
    {/*Your modal goes here*/}
    <YourModal setShowModal={setShowModal} />
  </ModalBase>

在胁迫回应容器中:

import React, { useEffect, useRef, useState } from "react";
import ReactDOM from "react-dom";

const modalRoot: HTMLElement | null = document.getElementById("modal-root");

const Modal: React.FC<{
children: React.ReactNode;
setShowModal: React.Dispatch<boolean>;
}> = ({ children, setShowModal }) => {
  const [el] = useState(document.createElement("div"));
  const outClick = useRef(el);

  useEffect(() => {
    const handleOutsideClick = (
      e: React.MouseEvent<HTMLDivElement, MouseEvent> | MouseEvent
    ) => {
      const { current } = outClick;
      console.log(current.childNodes[0], e.target);
      if (current.childNodes[0] === e.target) {
        setShowModal(false);
      }
    };
    if (modalRoot) {
      modalRoot.appendChild(el);
      outClick.current?.addEventListener(
        "click",
        (e) => handleOutsideClick(e),
        false
      );
    }
    return () => {
      if (modalRoot) {
        modalRoot.removeChild(el);
        el.removeEventListener("click", (e) => handleOutsideClick(e), false);
      }
    };
  }, [el, setShowModal]);

  return ReactDOM.createPortal(children, el);
};

export default Modal;
li9yvcax

li9yvcax7#

使用下面的onClick方法,

<div className='modal-backdrop' onClick={(e) => {
      if (e.target.className === 'modal-backdrop') {
        setShowModal(false)
      }
    }}></div>
<div className="modal">
   <div>I'm a modal!</div>
     <button onClick={() => setShowModal(false)}>close modal</button>
   </div>
</div>

.modal-backdrop {
  position: absolute;
  top: 0;
  left: 0;
  background: #252424cc;
  height: 100%;
  width: 100vw;
}
kxeu7u2r

kxeu7u2r8#

您可以检查event.target.className,如果它包含父类,您可以关闭模态,如下所示,如果您在弹出窗口div内单击,它将不会关闭:

handleClick = () => {
    if (e.target.className === "PARENT_CLASS") {
        this.setState(prevState => ({
            showModal: false
        }));
    }

    // You should use e.stopPropagation to prevent looping
    e.stopPropagation();
  };
kmbjn2e3

kmbjn2e39#

这对我很有效:

const [showModal, setShowModal] = React.useState(false)

React.useEffect(() => {
  document.body.addEventListener('click', () => {
    setShowModal(false)
  })
})

return <>
  <Modal
    style={{ display: showModal ? 'block' : 'none'}}
    onClick={(e) => e.stopPropagation()}
  />
  <button onClick={(e) => {
    e.stopPropagation()
    setShowModal(true)
  }}>Show Modal</button>
</>

相关问题