| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- import { useState, useEffect } from 'react'
- import { View, Text } from '@tarojs/components'
- import TDesignIcon from '../icon'
- import './index.css'
- interface ToastProps {
- visible?: boolean
- message?: string
- icon?: string
- theme?: 'loading' | 'success' | 'error' | 'warning'
- duration?: number
- placement?: 'top' | 'middle' | 'bottom'
- direction?: 'row' | 'column'
- showOverlay?: boolean
- preventScrollThrough?: boolean
- onClose?: () => void
- }
- export default function TDesignToast({
- visible = false,
- message = '',
- icon,
- theme,
- duration = 2000,
- placement = 'middle',
- direction = 'row',
- showOverlay = false,
- onClose
- }: ToastProps) {
- const [realVisible, setRealVisible] = useState(visible)
- const [transitionClass, setTransitionClass] = useState('')
- useEffect(() => {
- if (visible) {
- setRealVisible(true)
- setTransitionClass('tdesign-toast--enter')
- // 自动关闭
- if (duration > 0) {
- const timer = setTimeout(() => {
- handleClose()
- }, duration)
- return () => clearTimeout(timer)
- }
- } else {
- handleClose()
- }
- }, [visible, duration])
- const handleClose = () => {
- setTransitionClass('tdesign-toast--leave')
- setTimeout(() => {
- setRealVisible(false)
- onClose?.()
- }, 300)
- }
- const getIconName = () => {
- if (icon) return icon
- switch (theme) {
- case 'loading':
- return 'loading'
- case 'success':
- return 'check-circle'
- case 'error':
- return 'error'
- case 'warning':
- return 'warning'
- default:
- return undefined
- }
- }
- const getPlacementStyle = () => {
- switch (placement) {
- case 'top':
- return { top: '25%' }
- case 'bottom':
- return { top: '75%' }
- case 'middle':
- default:
- return { top: '45%' }
- }
- }
- const iconName = getIconName()
- const isLoading = theme === 'loading'
- if (!realVisible) {
- return null
- }
- return (
- <>
- {/* 遮罩层 */}
- {showOverlay && (
- <View
- className="tdesign-toast__overlay"
- style={{
- position: 'fixed',
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
- backgroundColor: 'rgba(0, 0, 0, 0.6)',
- zIndex: 11000
- }}
- onClick={handleClose}
- />
- )}
- {/* Toast 内容 */}
- <View
- className={`
- tdesign-toast
- tdesign-toast--${direction}
- ${theme ? `tdesign-toast--${theme}` : ''}
- ${message ? 'tdesign-toast--with-text' : ''}
- ${transitionClass}
- `}
- style={{
- position: 'fixed',
- left: '50%',
- transform: 'translate(-50%, -50%)',
- zIndex: 12001,
- ...getPlacementStyle()
- }}
- aria-role="alert"
- >
- <View className={`tdesign-toast__content tdesign-toast__content--${direction}`}>
- {isLoading && (
- <TDesignIcon
- name="loading"
- size={direction === 'row' ? '48rpx' : '64rpx'}
- color="#fff"
- className="tdesign-toast__loading"
- />
- )}
- {!isLoading && iconName && (
- <TDesignIcon
- name={iconName}
- size={direction === 'row' ? '48rpx' : '64rpx'}
- color="#fff"
- className={`tdesign-toast__icon tdesign-toast__icon--${direction}`}
- />
- )}
- {message && (
- <Text className={`tdesign-toast__text tdesign-toast__text--${direction}`}>
- {message}
- </Text>
- )}
- </View>
- </View>
- </>
- )
- }
|