react实现弹窗、弹窗的静态方法的方式

ReactDOM.createPortal(ReactNod,container)

实现弹窗的关键在于,如何将弹窗组件挂载到任意的dom上.这里react-dom中提供了一个方法,下面举个例子

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

const Modal = (props) => {
	const { container } = props;
		
	return ReactDOM.createPortal(
		// 这里可以是dom元素,也可以是react组件,还可以是react节点
		<div>我是弹窗的容器</div>,
		// 将传入的元素/组件/节点,挂载到container下面
		container
	)
}

这样一个简单的例子,就已经完成了一个组件的挂载,有的时候,我们需要在函数中,或是一个事件中使用一个消息弹窗.但是我们又不想使用一个消息组件.最好是有静态方法,调用一次,弹窗就弹一次,那么这个功能如何实现呢?

ReactDOM.render(ReactNode,container)

import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import styles from './index.module.less'

const Modal = (props) => {
  const { container } = props;

  return ReactDOM.createPortal(
    // 这里可以是dom元素,也可以是react组件,还可以是react节点
    <div style={{ position: 'absolute', top: '50%', left: '50%', zIndex: 99999999, width: '500px', height: '500px', backgroundColor: 'red' }}>我是弹窗的容器</div>,
    // 将传入的元素/组件/节点,挂载到container下面
    container
  )
}

const Message = (props) => {
  const { visible, onCancel, container, onFinish, msg, ...rest } = props;
  const [_container, setContainer] = useState(null);
  const timer = useRef<any>(null);

  useEffect(
    () => {
      if (visible) return;
      if (typeof onFinish === 'function') {
        onFinish();
      }
    },
    [visible]
  )

  useEffect(
    () => {
      setContainer(container || document.body)
    },
    [container]
  );

  useEffect(
    () => {
      const cb = (e) => {
        const ele = e.target;
        if (ele && ele.className !== styles.overlay) {
          onClose();
          onClear();
        }
      }

      document.addEventListener('click', cb);
      return () => {
        document.removeEventListener('click', cb);
      }
    },
    []
  );

  useEffect(
    () => {
      if (!!visible) {
        if (!!timer.current) clearTimeout(timer.current);
        timer.current = setTimeout(() => {
          onClose();
          onClear();
        }, 3000)
      } else {
        onClear();
      }
    },
    [visible, onCancel, onFinish]
  )

  function onClose() {
    if (typeof onCancel === 'function') {
      onCancel();
    }
  }

  function onClear() {
    clearTimeout(timer.current);
    timer.current = null;
  }

  console.log(_container)
  if (!_container) return null;
  return (
    <Modal
      className={styles.overlay}
      visible={visible}
      onClick={(e) => { e.stopImmediatePropagation() }}
      container={_container}
      {...rest}
    >
      <div>{msg}</div>
    </Modal>
  )
};

let msgBox: any = null;

// type弹窗类型,可以根据不同类型,渲染不同类型弹窗的样式
const MessageAPI = (type, msg, callBack) => {
  onCancel();

  msgBox = document.createElement('div');
  document.body.appendChild(msgBox);

  function onCancel() {
    if (!!msgBox) {
      ReactDOM.unmountComponentAtNode(msgBox);
    }
  }

  console.log(msgBox)

  ReactDOM.render(
    <Message
      visible={true}
      onCancel={onCancel}
      onFinish={() => !!callBack && callBack()}
      msg={msg}
    />,
    msgBox
  );
}

// 这样就可以通过Message.onSuccess("成功了")这样的静态方法,使用弹窗了
Message.onSuccess = (msg, callback?: any) => MessageAPI('success', msg, callback);
Message.onError = (msg, callback?: any) => MessageAPI('error', msg, callback);

export default Message;

效果图
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值