使用 React Hooks 在模态外部单击时关闭模态

问题描述 投票:0回答:4

我正在尝试创建一个弹出订阅框,只要单击关闭按钮或单击弹出窗口之外的任何位置,该框就会关闭。我创建了一个模态组件和一个状态

showModal
,用于切换该模态的可见性。我尝试将
setShowModal(false)
添加到外部
div
元素,但这只会禁用整个模式。每当我们在模态之外单击时,可以做什么来关闭模态。这就是我的主页的样子

const [showModal, setShowModal] = useState(false);

return (
    <>
      <div
        className="homepage"
        style={{
          filter: showModal ? "blur(8px)" : "none",
          minHeight:"80vh",
        }}
      >
        <section
          className="homepage-hero"
          style={{ paddingBottom:"-2rem", minHeight:"100vh" }}
        >
          <div className="hero-body">
            <div className="container">
              <div className="columns">
                <div className="column ">
                  <h1>
                    <span className="heading">
                      Finance <br />
                      Scheme
                    </span>
                    <br />
                  </h1>
                  <p>
                   Lorem Ipsum
                  </p>
                  <div className="is-hidden-tablet">

                  </div>
                  <div className="button-group">
                    <button
                      style={{
                        fontWeight: "600",
                        padding: "0.75em 1.9em",
                        borderRadius: "0px",
                        color: "white",
                        backgroundColor: "#24ca7a",
                        border: "1px solid #24ca7a",
                        cursor: "pointer",
                      }}
                      onClick={() => setShowModal(true)}
                    >
                      Download
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
      </div>
      {showModal && (
        <Modal
          modalId="signup-modal"
          onClose={() => setShowModal(false)}
          canDismiss={false}
          modalWidth="70%"
          style={{position:"fixed", top:"20", minHeight:"50vh"}}
          >        
          <div className="contact-us" style={{  margin:"20px"}}>
            <section className="contact-form"  >
              <div className="container">
                <div className="columns is-8 ">
                  <div
                    className="column is-half-desktop is-full-mobile container-content"
                    style={{ boxShadow: "none" }}
                  >
                    {submitted ? (
                      <div className="success">
                        <img src={confirmedIllus} alt="" />
                        <h2>Your details have been submitted successfully!</h2>
                      </div>
                    ) : (
                      <form onSubmit={handleOnSubmit} id="contact-form" >
                        <h1 className="heading" style={{ fontSize: "2rem" }}>
                          Your Details
                        </h1>
                        <br />
                        <div className="field">
                          <label className="label">Name</label>
                          <div className="control">
                            <input
                              className="input"
                              id="name"
                              value={name}
                              type="text"
                              placeholder="Your Full Name"
                              onChange={(e) => setName(e.target.value)}
                              required
                            />
                          </div>
                        </div>
                        <div className="field">
                          <label className="label">Email</label>
                          <div className="control ">
                            <input
                              className={`input ${isDanger}`}
                              id="email"
                              value={email}
                              type="email"
                              onChange={handleOnChange}
                              placeholder="Your Email"
                              required
                            />
                            {!validEmail && isDanger ? (
                              <span className="icon is-small is-right">
                                <i className="material-icons-round">warning</i>
                              </span>
                            ) : (
                              " "
                            )}
                          </div>
                          {!validEmail && isDanger ? (
                            <p className="help is-danger">{emailMessage}</p>
                          ) : (
                            ""
                          )}
                        </div>

                        <div className="field is-grouped submit-button-group">
                          <div className="control">
                            <button
                              style={{
                                cursor: !validEmail ? "not-allowed" : "pointer",
                              }}
                              className="button  submit-button"
                              id="submit-form"
                            >
                              Submit
                            </button>
                          </div>
                        </div>
                      </form>
                    )}
                  </div>
                  <div className="column is-half-desktop is-full-mobile " >
                    <img
                      src="/images/Ebook.svg"
                      className="is-hidden-mobile"
                      style={{ width: "70%", marginTop: "40%" }}
                    />
                    <div className=" font-blue bottom-text">
                      Fill your details to download the free <b> Ebook </b>
                    </div>
                  </div>
                </div>
              </div>
            </section>
          </div>
        </Modal>
      )}
    </>
  );
javascript reactjs react-hooks
4个回答
15
投票

您可以使用

useOnClickOutside
挂钩。该挂钩允许您检测指定元素之外的点击。

您必须导入以下内容

创建一个引用,将其添加到要检测外部点击的元素中

const ref = useRef();

我们的模式的状态

const [showModal, setShowModal] = useState(false);

调用钩子传入 ref 和在外部单击时调用的函数

useOnClickOutside(ref, () => setShowModal(false));

在此处渲染

返回(...);

//Hook

import { useEffect } from 'react';


export default function useOnClickOutside(ref, handler) {
  useEffect(
    () => {
      const listener = (event) => {
        // Do nothing if clicking ref's element or descendent elements
        if (!ref.current || ref.current.contains(event.target)) {
          return;
        }
        handler(event);
      };
      document.addEventListener("mousedown", listener);
      document.addEventListener("touchstart", listener);
      return () => {
        document.removeEventListener("mousedown", listener);
        document.removeEventListener("touchstart", listener);
      };
    },
    // Add ref and handler to effect dependencies
    // It's worth noting that because the passed-in handler is a new ...
    // ... function on every render that will cause this effect ...
    // ... callback/cleanup to run every render. It's not a big deal ...
    // ... but to optimize you can wrap handler in useCallback before ...
    // ... passing it into this hook.
    [ref, handler]
  );
}

在此处查看相关的 repl 输出 - https://spanishhotloaderprogram.thelovekesh.repl.co/


0
投票

为此,您可以将

tabIndex=-1
赋予模态 div,然后可以使用 onBlur 事件。

const [showModal, setShowModal] = useState(false);

return (
    <>
      <div
        className="homepage"
        style={{
          filter: showModal ? "blur(8px)" : "none",
          minHeight:"80vh",
        }}
      >
        <section
          className="homepage-hero"
          style={{ paddingBottom:"-2rem", minHeight:"100vh" }}
        >
          <div className="hero-body">
            <div className="container">
              <div className="columns">
                <div className="column ">
                  <h1>
                    <span className="heading">
                      Finance <br />
                      Scheme
                    </span>
                    <br />
                  </h1>
                  <p>
                   Lorem Ipsum
                  </p>
                  <div className="is-hidden-tablet">

                  </div>
                  <div className="button-group">
                    <button
                      style={{
                        fontWeight: "600",
                        padding: "0.75em 1.9em",
                        borderRadius: "0px",
                        color: "white",
                        backgroundColor: "#24ca7a",
                        border: "1px solid #24ca7a",
                        cursor: "pointer",
                      }}
                      onClick={() => setShowModal(true)}
                    >
                      Download
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
      </div>
      {showModal && (
        <Modal
          modalId="signup-modal"
          onBlur={() => setShowModal(false)}
          canDismiss={false}
          modalWidth="70%"
          style={{position:"fixed", top:"20", minHeight:"50vh"}}
          tabIndex={-1}
          >        
          <div className="contact-us" style={{  margin:"20px"}}>
            <section className="contact-form"  >
              <div className="container">
                <div className="columns is-8 ">
                  <div
                    className="column is-half-desktop is-full-mobile container-content"
                    style={{ boxShadow: "none" }}
                  >
                    {submitted ? (
                      <div className="success">
                        <img src={confirmedIllus} alt="" />
                        <h2>Your details have been submitted successfully!</h2>
                      </div>
                    ) : (
                      <form onSubmit={handleOnSubmit} id="contact-form" >
                        <h1 className="heading" style={{ fontSize: "2rem" }}>
                          Your Details
                        </h1>
                        <br />
                        <div className="field">
                          <label className="label">Name</label>
                          <div className="control">
                            <input
                              className="input"
                              id="name"
                              value={name}
                              type="text"
                              placeholder="Your Full Name"
                              onChange={(e) => setName(e.target.value)}
                              required
                            />
                          </div>
                        </div>
                        <div className="field">
                          <label className="label">Email</label>
                          <div className="control ">
                            <input
                              className={`input ${isDanger}`}
                              id="email"
                              value={email}
                              type="email"
                              onChange={handleOnChange}
                              placeholder="Your Email"
                              required
                            />
                            {!validEmail && isDanger ? (
                              <span className="icon is-small is-right">
                                <i className="material-icons-round">warning</i>
                              </span>
                            ) : (
                              " "
                            )}
                          </div>
                          {!validEmail && isDanger ? (
                            <p className="help is-danger">{emailMessage}</p>
                          ) : (
                            ""
                          )}
                        </div>

                        <div className="field is-grouped submit-button-group">
                          <div className="control">
                            <button
                              style={{
                                cursor: !validEmail ? "not-allowed" : "pointer",
                              }}
                              className="button  submit-button"
                              id="submit-form"
                            >
                              Submit
                            </button>
                          </div>
                        </div>
                      </form>
                    )}
                  </div>
                  <div className="column is-half-desktop is-full-mobile " >
                    <img
                      src="/images/Ebook.svg"
                      className="is-hidden-mobile"
                      style={{ width: "70%", marginTop: "40%" }}
                    />
                    <div className=" font-blue bottom-text">
                      Fill your details to download the free <b> Ebook </b>
                    </div>
                  </div>
                </div>
              </div>
            </section>
          </div>
        </Modal>
      )}
    </>
  );


0
投票

在 div className 主页中,单击时可以使用条件,如果 showModal 为 true --> setShowModal 为 false 就像

<div
 className="homepage"
 style={{
  filter: showModal ? "blur(8px)" : "none",
  minHeight: "80vh",
 }}
 onClick={() => showModal && setShowModal(false)}
>

0
投票

https://www.youtube.com/watch?v=J5hGX5_XZDk&t=737s 从7.00开始关注这个视频,他在react 18中使用了 useRef 来切换模块的最佳方法

© www.soinside.com 2019 - 2024. All rights reserved.