import * as ReactDOM from 'react-dom'; import { Component, createRef } from 'react'; import uniqueId from '../utils/uniqueId'; import noop from '../utils/noop'; import createElement from '../utils/dom/createElement'; import isBrowser from '../utils/isBrowser'; import Dialog, { IDialogProps } from './Dialog'; const dialogInstanceMap = new Map>(); function ensureUniqDialogInstance(dialogId: string) { if (dialogInstanceMap.has(dialogId)) { throw new Error(`Duplicate dialog id found: ${dialogId}`); } } function addDialogInstance( dialogId: string, ref: React.RefObject ) { dialogInstanceMap.set(dialogId, ref); } export interface ICloseDialogOption { triggerOnClose?: boolean; } interface IStandaloneDialogProps { options: Partial & { dialogId: string }; container: HTMLDivElement; } class StandaloneDialog extends Component { state = { visible: true, }; closeOptions: ICloseDialogOption = {}; close(options: ICloseDialogOption = {}) { this.closeOptions = options; this.setState({ visible: false, }); } onClosed = () => { const { options: { onClose }, container, } = this.props; const { triggerOnClose = true } = this.closeOptions; if (triggerOnClose && onClose) { onClose(); } ReactDOM.unmountComponentAtNode(container); }; onClose = (e: unknown) => { this.close({ triggerOnClose: e !== false, }); }; componentWillUnmount() { const { options: { dialogId }, } = this.props; dialogInstanceMap.delete(dialogId); } render() { const { options } = this.props; const { visible } = this.state; return ( ); } } export function closeDialog( dialogId: string, options: ICloseDialogOption = {} ) { const dialog = dialogInstanceMap.get(dialogId); if (!dialog) { return; } const wrapper = dialog.current; if (!wrapper) { return; } wrapper.close(options); } export interface IOpenDialogOption extends Omit { dialogId?: string; ref?: (ins: Dialog) => void | React.RefObject; parentComponent?: React.ReactInstance; onClose?: () => void; } /* 打开一个dialog,返回值是一个用来关闭dialog的函数。 */ export function openDialog(options: Partial = {}) { if (!isBrowser) return noop; const { dialogId = uniqueId('__zent-dialog__'), parentComponent } = options; ensureUniqDialogInstance(dialogId); const container = createElement('div'); // 确保多次调用close不会报错 const closeHandler = (triggerOnClose = true) => { closeDialog(dialogId, { triggerOnClose: triggerOnClose !== false, }); }; const render = parentComponent ? ReactDOM.unstable_renderSubtreeIntoContainer.bind( ReactDOM, parentComponent ) : ReactDOM.render; const ref = createRef(); // 不要依赖render的返回值,以后可能行为会改变 render( , container ); addDialogInstance(dialogId, ref); return closeHandler; }