React + TS + TailwindCSS 实现滚动字幕组件

作者:user 发布日期: 浏览量:34

接收参数

  • messages: string[]:必填,消息列表
  • direction?: ‘left’ | ‘right’ | ‘up’ | ‘down’:动画方向
  • interval?: number:动画间隔时间(秒)
  • duration?: number:动画持续时间(秒)
  • className?: string:自定义类名
  • type?: string:动画类型

组件代码

import React, { useState, useEffect, useRef } from 'react';

interface CarouselNotificationProps {
    messages: string[]; // 消息列表
    direction?: 'left' | 'right' | 'up' | 'down'; // 动画方向
    duration?: number; // 动画持续时间(秒)
    interval?: number; // 动画间隔时间(秒)
    className?: string; // 自定义类名
    type?: string; // 动画类型
}

const CarouselNotification: React.FC<CarouselNotificationProps> = ({ messages, direction = 'left', interval = 2, duration = 5, className = '', type = 'ease-in-out' }) => {
    const [currentIndex, setCurrentIndex] = useState<number>(0);
    const [message, setMessage] = useState<string>(messages[currentIndex]);
    const messageRef = useRef<HTMLDivElement | null>(null);
    let timer: NodeJS.Timeout | null = null; // 定时器

    // 根据方向获取动画类名
    const getAnimationClass = () => {
        switch (direction) {
            case 'left':
                return 'animate-left';
            case 'right':
                return 'animate-right';
            case 'up':
                return 'animate-up';
            case 'down':
                return 'animate-down';
            default:
                return 'animate-left';
        }
    };
    // 添加初始位置样式
    const getInitialPosition = () => {
        switch (direction) {
            case 'left':
                return 'translateX(100%)'
            case 'right':
                return 'translateX(-100%)'
            case 'up':
                return 'translateY(100%)'
            case 'down':
                return 'translateY(-100%)'
            default:
                return 'translateX(0%)'
        }
    };

    // 动画结束时的处理
    const handleAnimationEnd = () => {
        messageRef.current?.classList.remove(getAnimationClass());
        messageRef.current?.setAttribute('style', `transform: ${getInitialPosition()}`);
        timer = setTimeout(() => {
            let currIndex = currentIndex + 1;
            if (currIndex >= messages.length) {
                currIndex = 0;
            }
            setCurrentIndex(currIndex);
            setMessage(messages[currIndex]);
        }, interval * 1000);
    };

    useEffect(() => {
        messageRef.current?.classList.add(getAnimationClass());
        return () => {
            clearTimeout(timer as NodeJS.Timeout);
        }
    }, [messages, currentIndex]);

    return (
        <>
            <div className='w-full h-full relative overflow-hidden'>
                <div className={`initial-position absolute w-full h-full flex items-center justify-center ${className}`}
                    ref={messageRef}
                    onAnimationEnd={handleAnimationEnd}
                >
                    {message}
                </div>
            </div>
            <style>
                {`
                /* 基础样式 */
                .initial-position {
                    transform: ${getInitialPosition()};
                }

                /* 从右向左动画 */
                @keyframes slideLeft {
                    0% {
                        transform: translateX(100%);
                    }
                    50% {
                        transform: translateX(0%);
                    }
                    100% {
                        transform: translateX(-100%);
                    }
                }

                .animate-left {
                    animation: slideLeft ${duration}s ${type};
                }

                /* 从左向右动画 */
                @keyframes slideRight {
                    0% {
                        transform: translateX(-100%);
                    }
                    50% {
                        transform: translateX(0);
                    }
                    100% {
                        transform: translateX(100%);
                    }
                }

                .animate-right {
                    animation: slideRight ${duration}s  ${type};
                }

                /* 从上向下动画 */
                @keyframes slideDown {
                    0% {
                        transform: translateY(-100%);
                    }
                    50% {
                        transform: translateY(0);
                    }
                    100% {
                        transform: translateY(100%);
                    }
                }

                .animate-down {
                    animation: slideDown ${duration}s  ${type};
                }

                /* 从下向上动画 */
                @keyframes slideUp {
                    0% {
                        transform: translateY(100%);
                    }
                    50% {
                        transform: translateY(0);
                    }
                    100% {
                        transform: translateY(-100%);
                    }
                }

                .animate-up {
                    animation: slideUp ${duration}s  ${type};
                }
                `}
            </style>
        </>
    );
};

export default CarouselNotification;

使用示例

import CarouselNotification from "./CarouseNotification";

export default function Example() {
    const messages = [
        "1、欢迎来到我们的网站!",
        "2、今天的天气非常不错。",
        "3、我们有新的优惠活动,请查看。",
        "4、感谢您的支持,祝您购物愉快!",
        '5、这是另一个消息',
        '6、这是一条测试消息',
        '7、最新的产品已经上市了',
    ];
    return (
        <div className="min-h-screen bg-gray-100 p-8">
            <div style={{ padding: '20px', width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', flexDirection: 'column', gap: '50px' }}>
                <h1>轮播消息通知</h1>
                <h2>从右向左滚动</h2>
                <CarouselNotification messages={messages} interval={1} duration={5} direction="left" />

                <h2>从左向右滚动</h2>
                <CarouselNotification messages={messages} duration={5} direction="right" />

                <h2>从上向下滚动</h2>
                <CarouselNotification messages={messages} duration={3} direction="down" />

                <h2>从下向上滚动</h2>
                <CarouselNotification messages={messages} duration={3} direction="up" />
            </div>
        </div>
    )
}
已经是最后一篇了!