封装一个React的公共Toast组件

前言:很多toast的库不是自己理想的,也不太好看,下面封装一个TypeScript的Toast组件

先看效果: 组件源码贴到下面,可以随便修改成自己想要的样子

Toast.tsx:

import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle, Ref } from 'react';
import './index.scss';
import ReactDOM from 'react-dom';

interface ToastProps {
	widthStyle?: any;
	contentText?: string | null;
	containerEl?: any;
}

export interface ToastType {
	show: (text: string) => void;
}

const Toast = forwardRef((props: ToastProps, ref: Ref<ToastType>): any => {
	const ToastRef: React.RefObject<HTMLDivElement> = useRef(null);
	const [showToast, setShowToast] = useState<boolean>(false);
	const [fadeIn, setFadeIn] = useState<boolean>(false);
	const [contentText, setContentText] = useState<string>('');

	useImperativeHandle(ref, () => ({
		show: (text: string) => show(text),
	}));

	useEffect(() => {
		if (!showToast) return;
		const id = setTimeout(() => {
			setFadeIn(false);
		}, 2500);
		return () => clearTimeout(id);
	}, [showToast]);

	useEffect(() => {
		if (fadeIn || !showToast) return;
		const id = setTimeout(() => {
			setShowToast(false);
		}, 500);
		return () => clearTimeout(id);
	}, [fadeIn, showToast]);

	useEffect(() => {
		if (!('contentText' in props)) return;
		if (props.contentText) {
			setContentText(props.contentText || '');
			setFadeIn(true);
			setShowToast(true);
		} else if ('contentText' in props && props.contentText === null) {
			setFadeIn(false);
			setShowToast(false);
		}
	}, [props]);

	const show = (text: string) => {
		if (showToast) return;
		setContentText(text);
		setFadeIn(true);
		setShowToast(true);
	};

	return ReactDOM.createPortal(
		<div
			ref={ToastRef}
			className={`toast ${fadeIn ? `fadeIn` : `fadeOut`}`}
			style={{ display: showToast ? 'block' : 'none', ...props.widthStyle }}
		>
			<div className='toastInner'>
				<i className='icon'></i>
				<div className='content'>
					<span>{contentText}</span>
				</div>
			</div>
		</div>,
		props.containerEl || document.getElementById('wbContentContainer') || document.body,
	);
})

Toast.displayName = 'Toast';
export default Toast;

index.scss:

.toast {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 999999;
  display: none;
  transform: translate(-50%, -50%);
  &.fadeIn {
    animation: keyframes-fadeIn 0.5s forwards;
  }
  &.fadeOut {
    animation: keyframes-fadeOut 0.5s forwards;
  }
  .toastInner {
    position: relative;
    width: auto;
    max-width: 450px;
    min-height: 40px;
    padding: 0 18px 0 40px;
    background: rgba(0, 0, 0, 0.8);
    border-radius: 8px;
    box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.25);
    display: flex;
    align-items: center;
    .icon {
      position: absolute;
      bottom: 0;
      left: 18px;
      top: 12px;
      width: 16px;
      height: 16px;
      margin-right: 4px;
      background-image: url("写你的icon图片路径");
      background-position: 0 0;
      background-size: cover;
    }
    .content {
      color: #fff;
      padding: 8px 0;
      span {
        display: -webkit-box;
        font-size: 14px;
        font-family: PingFangSC-Regular, PingFang SC;
        font-weight: 400;
        color: #F46C60;
      }
    }
  }
}
@keyframes keyframes-fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
@keyframes keyframes-fadeOut {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

如何使用呢?

第一步在组件引入Toast:

import Toast from '@/components/Toast'; // 上面的Toast.tsx文件

第二步:放到dom里

<Toast ref={ToastRef}></Toast>

第三步:定义一个ToastRef的ref对象用于控制显隐

const ToastRef: any = useRef(null);

第四步:使用它

ToastRef.current?.show('小芳学前端')

最后显示效果就是这样子的,2500ms之后消失

 添加好友备注【进阶学习】拉你进技术交流群

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的React封装toast组件的示例: ```jsx import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; import './toast.css'; const Toast = ({ message, duration = 3000, onClose }) => { const [visible, setVisible] = useState(false); useEffect(() => { setVisible(true); const timer = setTimeout(() => { setVisible(false); onClose && onClose(); }, duration); return () => clearTimeout(timer); }, [duration, onClose]); return visible ? ( <div className="toast"> <div className="toast-message">{message}</div> </div> ) : null; }; const showToast = (message, duration = 3000, onClose) => { const div = document.createElement('div'); document.body.appendChild(div); ReactDOM.render( <Toast message={message} duration={duration} onClose={() => { ReactDOM.unmountComponentAtNode(div); onClose && onClose(); }} />, div ); }; export default showToast; ``` 这个组件包含一个`Toast`组件一个`showToast`函数。`Toast`组件接收`message`、`duration`和`onClose`作为属性,其中`message`表示要显示的消息,`duration`表示消息显示的时间(默认为3秒),`onClose`表示关闭消息时的回调函数。 `showToast`函数用于在页面上创建一个`Toast`组件并显示消息。它接收与`Toast`组件相同的属性,还有一个可选的`onClose`回调函数,用于在消息关闭时执行其他操作。 在使用时,可以像这样调用`showToast`函数: ```jsx import React from 'react'; import showToast from './toast'; const MyComponent = () => { const handleClick = () => { showToast('Hello, world!', 2000, () => console.log('Toast closed.')); }; return ( <button onClick={handleClick}>Show Toast</button> ); }; export default MyComponent; ``` 这个示例在点击按钮时显示一个消息框,显示2秒后关闭,并在关闭时输出一条消息到控制台。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值