You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-fast-marquee循环后图片缩放失效问题求助

问题分析

你遇到的问题根源在于react-fast-marquee的循环滚动机制:为实现无缝循环,组件会复制原始图片元素填充滚动容器。你的代码用document.getElementById('image-${index}')定位元素,但ID是唯一的,getElementById只会返回第一个匹配的原始元素,循环后出现的复制版0号、1号图片根本没被检测到,自然无法触发缩放。

解决方案

核心思路是放弃ID定位,改用类选择器+自定义数据属性跟踪所有图片元素(包括复制的),同时优化居中检测逻辑:

步骤1:修改图片容器标识

给ImageWrapper添加类名和data-index属性,存储原始图片的索引:

// 修改styled组件
const ImageWrapper = styled.div`
  transform: scale(${(props) => (props.center ? "1.1" : "1")});
  transition: transform 1s;
`;

// 渲染时添加类名和data-index
<ImageWrapper 
  key={index} 
  className="image-wrapper"
  data-index={index}
  center={isCenter}
>
  <LazyImg loading="lazy" src={listItem.image} />
</ImageWrapper>

步骤2:重写位置检测函数

通过类选择器获取所有图片元素,用data-index拿到原始索引,优化居中判断逻辑(检测图片中心是否接近视口中心):

const checkImagePosition = () => {
  const pageWidth = window.innerWidth;
  const pageCenterX = pageWidth / 2;
  const allImages = document.querySelectorAll('.image-wrapper');
  let currentCenterIndex = null;

  allImages.forEach(img => {
    const rect = img.getBoundingClientRect();
    const imageCenterX = rect.left + rect.width / 2;
    // 可根据需求调整误差范围
    if (Math.abs(imageCenterX - pageCenterX) <= 20) {
      currentCenterIndex = parseInt(img.dataset.index);
    }
  });

  // 仅当索引变化时更新状态,避免不必要重渲染
  if (currentCenterIndex !== centerImageIndex) {
    setCenterImageIndex(currentCenterIndex);
  }
};

步骤3:优化副作用监听

添加窗口resize事件监听,确保窗口大小变化时检测逻辑依然准确:

useEffect(() => {
  const intervalId = setInterval(checkImagePosition, 100);
  const handleResize = () => checkImagePosition();
  
  window.addEventListener('resize', handleResize);
  return () => {
    clearInterval(intervalId);
    window.removeEventListener('resize', handleResize);
  };
}, [centerImageIndex]);
修改后的完整代码
import React, { useEffect, useState } from "react";
import Marquee from "react-fast-marquee";
import styled from "styled-components";

const props = {
  Carousel: [
    { image: "/1.webp" },
    { image: "/2.webp" },
    { image: "/3.webp" },
    { image: "/4.webp" },
    { image: "/5.webp" },
  ],
};

function Gallery() {
  const [centerImageIndex, setCenterImageIndex] = useState(null);

  const checkImagePosition = () => {
    const pageWidth = window.innerWidth;
    const pageCenterX = pageWidth / 2;
    const allImages = document.querySelectorAll('.image-wrapper');
    let currentCenterIndex = null;

    allImages.forEach(img => {
      const rect = img.getBoundingClientRect();
      const imageCenterX = rect.left + rect.width / 2;
      if (Math.abs(imageCenterX - pageCenterX) <= 20) {
        currentCenterIndex = parseInt(img.dataset.index);
      }
    });

    if (currentCenterIndex !== centerImageIndex) {
      setCenterImageIndex(currentCenterIndex);
    }
  };

  useEffect(() => {
    const intervalId = setInterval(checkImagePosition, 100);
    const handleResize = () => checkImagePosition();
    
    window.addEventListener('resize', handleResize);
    return () => {
      clearInterval(intervalId);
      window.removeEventListener('resize', handleResize);
    };
  }, [centerImageIndex]);

  return (
    <Container>
      <ImagesContainer>
        <Marquee speed={100} pauseOnHover>
          {props?.Carousel.map((listItem, index) => {
            const isCenter = index === centerImageIndex;
            return (
              <ImageWrapper 
                key={index} 
                className="image-wrapper"
                data-index={index}
                center={isCenter}
              >
                <LazyImg loading="lazy" src={listItem.image} />
              </ImageWrapper>
            );
          })}
        </Marquee>
      </ImagesContainer>
    </Container>
  );
}

const Container = styled.div`
  width: 100%;
`;

const ImagesContainer = styled.div`
`;

const ImageWrapper = styled.div`
  transform: scale(${(props) => (props.center ? "1.1" : "1")});
  transition: transform 1s;
`;

const LazyImg = styled.img`
  width: 300px;
  border-radius: 50px;
  background: #e0e0e0;
  box-shadow: 20px 20px 60px #bebebe, -20px -20px 60px #ffffff;
  margin: 40px 40px;
`;

export default Gallery;

关键优化点

  • 用document.querySelectorAll('.image-wrapper')获取所有图片元素(包括复制的),解决ID重复导致的元素遗漏问题
  • 检测图片中心与视口中心的距离,比检测元素X坐标更准确
  • 仅当中心索引变化时更新状态,减少不必要的组件重渲染
  • 添加窗口resize监听,适配窗口大小变化场景

内容的提问来源于stack exchange,提问作者Anders Kitson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:50:54