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

使用array.map渲染的元素如何在Framer Motion中单独触发进入视口动画

Framer Motion map渲染元素单独触发视口动画解决方案

问题根因

  • 父容器绑定ref:所有子元素复用父容器的同一个inView状态,父容器进入视口时状态批量更新,3个div动画同步触发
  • 循环绑定同一ref:单个ref变量在map遍历过程中会被反复赋值覆盖,最终仅存储最后一个div的引用,因此只有最后一个元素进入视口时才会触发全局共享的inView状态,全量div统一触发动画

最简实现方案

核心思路是将单个待渲染的div封装为独立子组件,每个子组件内部独立维护自己的视口检测ref、动画状态,天然隔离互不干扰。

步骤1:封装独立动画子组件

import { motion, useInView, useAnimation } from "framer-motion";
import { useRef, useEffect } from "react";

const AnimatedDiv = ({ content }) => {
  // 每个组件内部独立的动画控制器、ref、视口检测状态
  const controls = useAnimation();
  const itemRef = useRef(null);
  const isInView = useInView(itemRef, { 
    once: true, // 仅触发一次,不需要可删除
    margin: "-50px 0px" // 自定义触发阈值,元素进入视口50px时触发
  });

  useEffect(() => {
    if (isInView) {
      controls.start("show");
    }
  }, [controls, isInView]);

  return (
    <motion.div
      ref={itemRef}
      initial="hide"
      animate={controls}
      variants={{
        hide: { opacity: 0, y: 20 },
        show: { opacity: 1, y: 0, transition: { duration: 0.5 } }
      }}
    >
      {content}
    </motion.div>
  );
};

步骤2:父组件遍历渲染子组件

const ParentComponent = () => {
  // 你的原始数据列表
  const dataList = [
    { id: 1, content: "第一个div内容" },
    { id: 2, content: "第二个div内容" },
    { id: 3, content: "第三个div内容" }
  ];

  return (
    <div className="父容器样式">
      {dataList.map(item => (
        <AnimatedDiv key={item.id} content={item.content} />
      ))}
    </div>
  );
};

可选替代方案(不抽离组件)

如果不想封装子组件,也可以通过ref数组存储每个元素的引用,单独维护每个元素的inView状态即可,但代码冗余度更高,不优先推荐。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 12:15:03