3D跑马灯特效组件

使用方式

  npm i react-carousel-new

react-carousel-new - npm

代码示例👇:

import React from 'react';
import { Carousel } from 'react-carousel-new';


const Com: React.FC = () => {
  return (
    <div style={{
      width: '100%',
      height: '500px',
    }}>
      <Carousel 
      centerImage="https://img0.baidu.com/it/u=1241597997,3770576363&fm=253&fmt=auto&app=138&f=JPEG?w=732&h=500"
      surroundingImages={[
        "https://img0.baidu.com/it/u=1241597997,3770576363&fm=253&fmt=auto&app=138&f=JPEG?w=732&h=500",
        "https://img0.baidu.com/it/u=1241597997,3770576363&fm=253&fmt=auto&app=138&f=JPEG?w=732&h=500",
        "https://img0.baidu.com/it/u=1241597997,3770576363&fm=253&fmt=auto&app=138&f=JPEG?w=732&h=500",
        "https://img0.baidu.com/it/u=1241597997,3770576363&fm=253&fmt=auto&app=138&f=JPEG?w=732&h=500",
        "https://img0.baidu.com/it/u=1241597997,3770576363&fm=253&fmt=auto&app=138&f=JPEG?w=732&h=500",
        "https://img0.baidu.com/it/u=1241597997,3770576363&fm=253&fmt=auto&app=138&f=JPEG?w=732&h=500",
      ]}
      />
    </div>
  );
};

export default Com;

API

参数说明类型默认值
centerImage中心图片string-
surroundingImages周围图片string[]-
speed旋转速度number0.5
radius半径number300
className自定义类名string-

 

实现原理

3D跑马灯(旋转木马)特效主要通过CSS 3D变换和JavaScript动画控制实现。核心是利用transform属性的rotateYtranslateZ组合,将平面元素转换为三维空间中的环形布局。

旋转动画通过持续修改旋转角度来实现,通常使用requestAnimationFrame保证流畅性。元素在Y轴旋转的同时沿Z轴位移,形成立体环绕效果。

React组件实现方法

基础组件结构

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

interface CarouselProps {
  items: Array<{ id: string; content: React.ReactNode }>;
  radius?: number;
  speed?: number;
}

const Carousel3D: React.FC<CarouselProps> = ({ 
  items, 
  radius = 300, 
  speed = 0.5 
}) => {
  const [angle, setAngle] = useState(0);
  const animationRef = useRef<number>();

  useEffect(() => {
    const animate = () => {
      setAngle(prev => (prev + speed) % 360);
      animationRef.current = requestAnimationFrame(animate);
    };
    animationRef.current = requestAnimationFrame(animate);
    
    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, [speed]);

  return (
    <div className="carousel-container">
      {items.map((item, index) => {
        const itemAngle = (index * (360 / items.length)) + angle;
        return (
          <div 
            key={item.id}
            className="carousel-item"
            style={{
              transform: `rotateY(${itemAngle}deg) translateZ(${radius}px)`
            }}
          >
            {item.content}
          </div>
        );
      })}
    </div>
  );
};

CSS样式配置

.carousel-container {
  position: relative;
  width: 100%;
  height: 400px;
  perspective: 1000px;
  transform-style: preserve-3d;
}

.carousel-item {
  position: absolute;
  width: 200px;
  height: 200px;
  top: 50%;
  left: 50%;
  transform-origin: center center;
  transition: transform 0.1s ease-out;
  backface-visibility: visible;
}

高级功能扩展

自动暂停与交互控制

const [isPlaying, setIsPlaying] = useState(true);

useEffect(() => {
  if (!isPlaying && animationRef.current) {
    cancelAnimationFrame(animationRef.current);
    return;
  }
  // ...原有动画逻辑
}, [isPlaying, speed]);

const handleItemClick = (index: number) => {
  const targetAngle = 360 - (index * (360 / items.length));
  setAngle(targetAngle);
};

响应式半径调整

const [dynamicRadius, setDynamicRadius] = useState(radius);

useEffect(() => {
  const handleResize = () => {
    setDynamicRadius(Math.min(radius, window.innerWidth * 0.3));
  };
  window.addEventListener('resize', handleResize);
  return () => window.removeEventListener('resize', handleResize);
}, [radius]);

性能优化建议

使用will-change属性提前告知浏览器可能的变化

.carousel-item {
  will-change: transform;
}

对静态内容使用React.memo

const MemoizedItem = React.memo(({ content }: { content: React.ReactNode }) => (
  <div className="item-content">{content}</div>
));
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值