使用reactjs打开选定的模态

时间:2019-04-25 14:17:13

标签: reactjs

我正在此question

上使用代码共享

该代码仅适用于一个模态,我试图添加多个,但是当我第一次单击它时,所有模态都被触发,然后它正常工作,这是我面临的唯一问题

Modal.js

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

const Modal = ({ isOpen, type, onClose, children }) => {
  const modalEl = useRef(null);
  const handleCoverClick = e => {
    if (e.target.hasAttribute("modal")) {
      onClose();
    }
  };

  useEffect(() => {
    const handleAnimationEnd = event => {
      if (isOpen.type === type && isOpen.modal) {
        if (!isOpen.modal) {
          event.target.classList.remove("show");
          event.target.classList.add("hide");
        } else {
          event.target.classList.remove("hide");
          event.target.classList.add("show");
        }
      }
    };
    modalEl.current.addEventListener("animationend", handleAnimationEnd);

    return () =>
      modalEl.current.removeEventListener("animationend", handleAnimationEnd);
  }, [isOpen]);

  return createPortal(
    <>
      <div
        className={`ModalCover ${isOpen ? "show" : "hide"}`}
        onClick={handleCoverClick}
        modal="true"
      />
      <div
        className={`
            ModalContainer
            ${isOpen.type === type && isOpen.modal ? "slide-up" : "slide-down"}
            ${!modalEl.current && "hide"}
            `}
        ref={modalEl}
      >
        {children}
      </div>
    </>,
    document.body
  );
};

export default Modal;

Style.css

.App {
  font-family: sans-serif;
  text-align: center;
}

.show {
  display: block;
}

.hide {
  display: none;
}

.slide-up {
  transform: translateY(0%);
  animation: slide-up 0.5s forwards;
}

.slide-down {
  transform: translateY(100%);
  animation: slide-down 0.5s forwards;
}

@keyframes slide-up {
  0% {
    transform: translateY(100%);
  }
  100% {
    transform: translateY(0%);
  }
}

@keyframes slide-down {
  0% {
    transform: translateY(0%);
  }
  100% {
    transform: translateY(100%);
  }
}

.ModalCover {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 10;
  background-color: rgba(0, 0, 0, 0.15);
}

.ModalContainer {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 400px;
  margin-top: calc(100vh - 400px);
  z-index: 20;
}

Index.js

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

import Modal from "./Modal";

import "./styles.css";

function App() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <div className="App">
      <Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
        <div>
          <h3>Coockie</h3>
          <p>content about coockies</p>
          <button
            aria-label="Close this popup"
            onClick={() => setIsOpen({ type: "coockie", modal: false })}
            className="closeBtn"
          >
            x
          </button>
        </div>
      </Modal>

      <Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
        <div>
          <h3>About us</h3>
          <p>content about us</p>
          <button
            aria-label="Close this popup"
            onClick={() => setIsOpen({ type: "about-us", modal: false })}
            className="closeBtn"
          >
            x
          </button>
        </div>
      </Modal>

      <button onClick={() => setIsOpen({ content: "coockie", modal: true })}>
        coockie modal
      </button>
      <button onClick={() => setIsOpen({ content: "about-us", modal: true })}>
        about us modal
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
  • 实时代码为here

  • ,而这个link的代码使用一种模态

1 个答案:

答案 0 :(得分:0)

更正:-

1)我们不希望在isOpen为真之前渲染模式

2)根据ModalContainer的标志更正显示和隐藏,而不是在参考值modalEl.current中填充当前值。

3)您对两个模态使用相同的状态和更新方法。创建单独的状态,您应该一切顺利。目前,我有isOpen1isOpen2这两个名字,但是您可以给出更有意义的名字。

// index.js

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

import Modal from "./Modal";

import "./styles.css";

function App() {
  const [isOpen1, setIsOpen1] = useState(false);
  const [isOpen2, setIsOpen2] = useState(false);

  return (
    <div className="App">
      <>
        {isOpen1 && (
          <Modal isOpen={isOpen1} onClose={() => setIsOpen1(false)}>
            <div>
              <h3>Coockie</h3>
              <p>content about coockies</p>
              <button
                aria-label="Close this popup"
                onClick={() => setIsOpen1(false)}
                className="closeBtn"
              >
                x
              </button>
            </div>
          </Modal>
        )}
      </>
      <>
        {isOpen2 && (
          <Modal isOpen={isOpen2} onClose={() => setIsOpen2(false)}>
            <div>
              <h3>About us</h3>
              <p>content about us</p>
              <button
                aria-label="Close this popup"
                onClick={() => setIsOpen2(false)}
                className="closeBtn"
              >
                x
              </button>
            </div>
          </Modal>
        )}
      </>

      <button onClick={() => setIsOpen1(true)}>coockie modal</button>
      <button onClick={() => setIsOpen2(true)}>about us modal</button>
    </div>
  );
}

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

// Modal.js

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

const Modal = ({ isOpen, onClose, children }) => {
  const modalEl = useRef(null);
  const handleCoverClick = e => {
    if (e.target.hasAttribute("modal")) {
      onClose();
    }
  };

  useEffect(() => {
    const handleAnimationEnd = event => {
      if (!isOpen) {
        event.target.classList.remove("show");
        event.target.classList.add("hide");
      } else {
        event.target.classList.remove("hide");
        event.target.classList.add("show");
      }
    };
    const modalRef = modalEl.current;

    modalEl.current.addEventListener("animationend", handleAnimationEnd);

    return () =>
      modalRef.removeEventListener("animationend", handleAnimationEnd);
  }, [isOpen]);

  return createPortal(
    <>
      <div
        className={`ModalCover ${isOpen ? "show" : "hide"}`}
        onClick={handleCoverClick}
        modal="true"
      />
      <div
        className={`
          ModalContainer
          ${isOpen ? "slide-up show" : "slide-down hide"}
        `}
        ref={modalEl}
      >
        {children}
      </div>
    </>,
    document.body
  );
};

export default Modal;