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

React实现网格项滚动时收缩与展开动画的方案求助

React实现滚动驱动网格项收缩/展开动画方案

核心实现思路

  • 监听页面滚动状态,获取每个网格项与视口的相对位置
  • 根据元素进入/离开视口的比例,计算动画进度值
  • 基于进度值动态修改网格项的样式属性(高度、缩放、透明度等),实现收缩/展开的过渡效果

推荐工具包

  • react-intersection-observer:简化元素视口监听逻辑,无需手动处理滚动事件,支持多阈值触发,适合基础滚动动画场景
  • framer-motion:React生态的专业动画库,内置滚动驱动动画、弹簧缓动等特性,能快速实现平滑且精细的过渡效果
  • gsap:功能强大的动画引擎,支持滚动触发、时间线控制,适合需要高度自定义的复杂动画需求

具体实现步骤(结合你的代码)

方案1:用react-intersection-observer实现基础监听

  1. 安装依赖:
npm install react-intersection-observer
  1. 修改列表渲染代码:
import { useInView } from 'react-intersection-observer';

{projects?.map((projectData) => {
  const project = tData(projectData);
  const slug = toKebabCase(`${projectData.en?.client}-${projectData.en?.project}`);
  
  // 配置视口监听,设置全范围阈值以获取精确的进入比例
  const [ref, , entry] = useInView({
    threshold: Array.from({ length: 101 }, (_, i) => i / 100),
    triggerOnce: false, // 支持滚动来回触发动画
  });

  // 计算动画进度:0为完全在视口外,1为完全进入视口
  const progress = entry?.intersectionRatio || 0;

  // 根据进度动态设置样式,模拟收缩/展开效果
  const itemStyle = {
    backgroundImage: `url(${project?.mainImage})`,
    height: `${60 + progress * 40}vh`, // 从60vh展开到100vh
    transform: `scale(${0.9 + progress * 0.1})`, // 从0.9缩放到1
    opacity: 0.7 + progress * 0.3, // 从半透明过渡到完全不透明
    transition: 'all 0.3s ease-out', // 平滑过渡
  };

  return (
    <div
      key={projectData.id}
      className="projects-grid-item"
      ref={ref}
      style={itemStyle}
    >
      <div className="project-content-wrapper">
        <div className="nox-h-4">
          <Link href={`${PROJECTS_ROUTE}/${slug}`}>
            <a>
              {project?.client} - {project?.project}
            </a>
          </Link>
        </div>
        <div className="additional-info-wrapper nox-body-1">
          <div className="services">{project?.services}</div>
          <div>{project?.year}</div>
        </div>
      </div>
    </div>
  );
})}

方案2:用framer-motion实现滚动驱动动画

  1. 安装依赖:
npm install framer-motion
  1. 修改列表渲染代码:
import { motion, useScroll, useTransform } from 'framer-motion';

// 在组件内部初始化滚动监听
const { scrollYProgress } = useScroll();

{projects?.map((projectData, index) => {
  const project = tData(projectData);
  const slug = toKebabCase(`${projectData.en?.client}-${projectData.en?.project}`);
  
  // 为每个网格项设置专属的滚动触发区间(可根据布局调整参数)
  const start = index * 0.3;
  const end = start + 0.3;

  // 将滚动进度映射为动画属性值
  const height = useTransform(scrollYProgress, [start, end], ['60vh', '100vh']);
  const scale = useTransform(scrollYProgress, [start, end], [0.9, 1]);
  const opacity = useTransform(scrollYProgress, [start, end], [0.7, 1]);

  return (
    <motion.div
      key={projectData.id}
      className="projects-grid-item"
      style={{
        backgroundImage: `url(${project?.mainImage})`,
        height,
        scale,
        opacity,
      }}
    >
      <div className="project-content-wrapper">
        <div className="nox-h-4">
          <Link href={`${PROJECTS_ROUTE}/${slug}`}>
            <a>
              {project?.client} - {project?.project}
            </a>
          </Link>
        </div>
        <div className="additional-info-wrapper nox-body-1">
          <div className="services">{project?.services}</div>
          <div>{project?.year}</div>
        </div>
      </div>
    </motion.div>
  );
})}

注意事项

  • 先确保基础网格布局(CSS Grid/Flex)已完成,保证每个项的初始空间符合需求
  • 动画参数(高度范围、缩放比例、过渡时长)可根据目标网站效果调整
  • 若手动实现滚动监听,需添加防抖逻辑避免频繁重渲染,优化性能

内容的提问来源于stack exchange,提问作者Zura Sudadze

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:36:27