No Description

index.tsx 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import React from "react";
  2. import ReactDOM from "react-dom";
  3. import { createPortal } from "react-dom";
  4. import { isBrowser } from "../Utils/utils";
  5. import styles from "./Modal.less";
  6. export interface ModalProps {
  7. visible: boolean;
  8. onCancel: (e: any) => void;
  9. container?: HTMLElement;
  10. }
  11. export class Modal extends React.PureComponent<ModalProps> {
  12. static hasShowWarning = false;
  13. render() {
  14. if (!isBrowser()) return null; // 服务端无需渲染下列代码,渲染也会出错
  15. const DEFAULT_CONTAINER: HTMLElement | null = document.getElementById(
  16. "container"
  17. );
  18. const { children, visible, onCancel, container } = this.props;
  19. let finalMountContainer: HTMLElement;
  20. if (!container) {
  21. if (!DEFAULT_CONTAINER) {
  22. if (!Modal.hasShowWarning) {
  23. Modal.hasShowWarning = true;
  24. }
  25. finalMountContainer = document.body;
  26. } else {
  27. if (!Modal.hasShowWarning) {
  28. Modal.hasShowWarning = true;
  29. }
  30. finalMountContainer = DEFAULT_CONTAINER;
  31. }
  32. } else {
  33. finalMountContainer = container;
  34. }
  35. return (
  36. visible &&
  37. createPortal(
  38. <div className={styles.wrapper}>
  39. <div className={styles.overlay} onClick={onCancel} />
  40. <div className={styles.container}>{children}</div>
  41. </div>,
  42. finalMountContainer
  43. )
  44. );
  45. }
  46. }
  47. export interface ModalCMDOptions {
  48. children: any;
  49. container?: HTMLElement;
  50. options?: {
  51. mask?: true;
  52. };
  53. }
  54. export interface ModalCMDRecord {
  55. modalInstance: HTMLElement;
  56. }
  57. export class ModalCMD {
  58. static currentModal: ModalCMDRecord[] = [];
  59. constructor() {
  60. ModalCMD.currentModal = [];
  61. }
  62. private static recordModal(record: ModalCMDRecord) {
  63. ModalCMD.currentModal.push(record);
  64. }
  65. private static delModal() {
  66. return ModalCMD.currentModal.pop();
  67. }
  68. static show({ children, container }: ModalCMDOptions) {
  69. const modalInstance = document.createElement("div");
  70. let targetMountDom = container ? container : document.body;
  71. targetMountDom.appendChild(modalInstance);
  72. ReactDOM.render(
  73. <>
  74. <div
  75. style={{
  76. position: "fixed",
  77. top: 0,
  78. bottom: 0,
  79. left: 0,
  80. right: 0,
  81. zIndex: 1000
  82. }}
  83. >
  84. <div
  85. style={{
  86. position: "absolute",
  87. top: 0,
  88. bottom: 0,
  89. left: 0,
  90. right: 0,
  91. background: "rgba(0,0,0,1)",
  92. opacity: 0.6,
  93. zIndex: -1
  94. }}
  95. onClick={() => {
  96. ModalCMD.hide(ModalCMD.currentModal.length);
  97. }}
  98. />
  99. <div
  100. style={{
  101. position: "absolute",
  102. top: "50%",
  103. left: "50%",
  104. transform: "translate(-50%, -50%)"
  105. }}
  106. >
  107. {children}
  108. </div>
  109. </div>
  110. </>,
  111. modalInstance
  112. );
  113. this.recordModal({
  114. modalInstance
  115. });
  116. }
  117. static hide(targetId?: string | number) {
  118. const popModalRecord: ModalCMDRecord | undefined = this.delModal();
  119. if (popModalRecord && popModalRecord.modalInstance) {
  120. ReactDOM.unmountComponentAtNode(popModalRecord.modalInstance);
  121. const { parentNode } = popModalRecord.modalInstance;
  122. parentNode && parentNode.removeChild(popModalRecord.modalInstance);
  123. }
  124. }
  125. }
  126. export default Modal;