当前位置: 首页 > news >正文

react 封装无缝滚动组件

记录,以防忘记

SeamlessScroll.tsx

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

interface SeamlessScrollProps {
    children: React.ReactNode;
    speed?: number; // 滚动速度,单位:像素/秒
    minItems?: number; // 最小项目数量,默认3个
    className?: string;
    style?: React.CSSProperties;
}

/**
 * 无缝滚动组件(从下往上滚动)
 * @param children - 需要滚动的内容
 * @param speed - 滚动速度,默认 50 像素/秒
 * @param minItems - 最小项目数量,默认3个,只有超过这个数量才会滚动
 * @param className - 自定义类名
 * @param style - 自定义样式
 */
const SeamlessScroll = ({ children, speed = 50, minItems = 3, className = '', style = {} }: SeamlessScrollProps) => {
    const containerRef = useRef<HTMLDivElement>(null);
    const contentRef = useRef<HTMLDivElement>(null);
    const [isHovered, setIsHovered] = useState(false);
    const animationFrameRef = useRef<number>();
    const lastTimeRef = useRef<number>(0);
    const positionRef = useRef<number>(0);
    const [shouldScroll, setShouldScroll] = useState(false);

    // 检查是否需要滚动
    useEffect(() => {
        if (contentRef.current) {
            const itemCount = React.Children.count(children);
            setShouldScroll(itemCount > minItems);
        }
    }, [children, minItems]);

    // 计算滚动距离
    const calculateScrollDistance = (deltaTime: number) => {
        return (speed * deltaTime) / 1000; // 将速度转换为每毫秒的滚动距离
    };

    // 处理滚动动画
    const handleScroll = (timestamp: number) => {
        if (!containerRef.current || !contentRef.current || !shouldScroll) return;

        const deltaTime = timestamp - lastTimeRef.current;
        lastTimeRef.current = timestamp;

        const scrollDistance = calculateScrollDistance(deltaTime);
        const content = contentRef.current;

        // 更新位置
        positionRef.current += scrollDistance;

        // 当滚动到一半时重置位置
        if (positionRef.current >= content.offsetHeight / 2) {
            positionRef.current = 0;
        }

        // 应用变换
        content.style.transform = `translateY(-${positionRef.current}px)`;

        if (!isHovered) {
            animationFrameRef.current = requestAnimationFrame(handleScroll);
        }
    };

    // 开始滚动
    useEffect(() => {
        if (!isHovered && shouldScroll) {
            lastTimeRef.current = performance.now();
            animationFrameRef.current = requestAnimationFrame(handleScroll);
        }

        return () => {
            if (animationFrameRef.current) {
                cancelAnimationFrame(animationFrameRef.current);
            }
        };
    }, [isHovered, speed, shouldScroll]);

    // 复制内容以实现无缝滚动
    const duplicatedContent = (
        <div
            ref={contentRef}
            style={{ display: 'block', width: '100%', willChange: 'transform', transition: 'none' }}        >
            {children}
            {shouldScroll && children}
        </div>
    );

    return (
        <div
            ref={containerRef}
            className={`seamless-scroll ${className}`}
            style={{
                position: 'relative',
                overflow: 'hidden',
                ...style,
            }}
            onMouseEnter={() => setIsHovered(true)}
            onMouseLeave={() => setIsHovered(false)}
        >
            {duplicatedContent}
        </div>
    );
};

export default SeamlessScroll; 

使用

<SeamlessScroll speed={30} minItems={4} style={{ height: '700px' }}>
    <div style={{ padding: '10px' }}>
        <List dataSource={data} renderItem={(item) => (
            <List.Item>
                <Card style={{ width: '100%' }}>
                    <h3>{item.title}</h3>
                    <p>{item.content}</p>
                </Card>
            </List.Item>
        )}
        />
    </div>
</SeamlessScroll>

相关文章:

  • get_seed协议
  • 躺平生产力
  • 如何一键安装所有Python项目的依赖!
  • 5.1 WPF路由事件以及文本样式
  • C笔记20250325
  • Golang使用 ip2region 查询IP的地区信息
  • 某Bzhan登录逆向(纯算法)
  • WSL 2是什么: Docker Desktop 默认依赖 WSL 2
  • 求最大公约数与最小公倍数
  • C#TCP通讯封装服务器工具类
  • 19、练习题
  • 从物理学到机器学习:用技术手段量化分析职场被动攻击行为
  • 【自学笔记】.NET基础知识点总览-持续更新
  • Opencv 图像读取与保存问题
  • RHCA核心课程技术解析4:红帽服务管理与自动化深度实践
  • Leetcode 背包问题笔记
  • python基础--类
  • python三大库之--numpy(一)
  • SQLAlchemy 支持特殊字符
  • 16. 最接近的三数之和
  • 水库信息化网站建设/福州百度网站快速优化
  • 网站更新维护/社群推广平台
  • 宝鸡专业做网站/新闻稿范文
  • 做web网站挣钱么/怎么优化自己公司的网站
  • 刚开始做网站布局很吃力 怎么办/谷歌排名优化入门教程
  • 网站flsh怎么做/优秀网页设计作品