1

我正在尝试使用 Framer Motion 和react-intersection-observer包将相同的动画分配给组件的多个实例

import { useEffect, useRef, useCallback } from "react";

import { motion, useAnimation } from "framer-motion";
import { useInView } from "react-intersection-observer";


const levels = [
    {
        title: "GROUP LESSONS",
        description:
            "Lorem ipsum",
    },
    {
        title: "WORKSHOPS",
        description:
            "Lorem ipsum",
    },

];

const container = {
    show: {
        transition: {
            staggerChildren: 0.2,
        },
    },
};

const item = {
    hidden: { opacity: 0, x: 200 },
    show: {
        opacity: 1,
        x: 0,
        transition: {
            ease: [0.6, 0.01, -0.05, 0.95],
            duration: 1.6,
        },
    },
};



const Levels = () => {
        const animation = useAnimation();
        const [levelRef, inView] = useInView({
        triggerOnce: true,
     });

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


    return (
        <LevelsContainer>
            {levels.map((level, index) => {
                return (
                    <LevelsWrapper
                        key={index}
                        ref={levelRef}
                        animate={animation}
                        initial="hidden"
                        variants={container}
                    >
                        <Level variants={item}>
                            <Title>{level.title}</Title>
                            <Description>{level.description}</Description>
                        </Level>
                    </LevelsWrapper>
                );
            })}
        </LevelsContainer>
    );
};

这会导致动画仅在滚动到最后一个 LevelWrapper 组件时加载。然后将“inView”设置为 true,所有组件同时进行动画处理。在 react-intersection-observer 包文档中,有一些关于在单个 useCallback 中包装多个 ref 分配的信息,所以我尝试过:

const animation = useAnimation();
    const ref = useRef();
    const [levelRef, inView] = useInView({
        triggerOnce: true,
    });

    const setRefs = useCallback(
        (node) => {
            ref.current = node;
            levelRef(node);
        },
        [levelRef]
    );

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

    return (
        <LevelsContainer>
            {levels.map((level, index) => {
                return (
                    <LevelsWrapper
                        key={index}
                        ref={setRefs}
                        animate={animation}
                        initial="hidden"
                        variants={container}
                    >
                        <Level variants={item}>
                            <Title>{level.title}</Title>
                            <Description>{level.description}</Description>
                        </Level>
                    </LevelsWrapper>
                );
            })}
        </LevelsContainer>
    );

但是动画仍然不会为每个 LevelWrapper 组件单独触发。发生了什么?

4

1 回答 1

1

不知道为什么问题中的代码不起作用,但我发现可以在不使用 useEffect、useRef、useCallback、、useAnimation 或 useInView 的情况下达到最终结果。

在 Framer Motion 文档中:

Motion 使用一组简单但功能强大的 UI 手势识别器扩展了 React 提供的基本事件侦听器集。

它目前支持悬停、点击、平移、视口和拖动手势检测。每个手势都有一系列事件侦听器,您可以将它们附加到您的运动组件。

然后应用这里解释的内容:https ://www.framer.com/docs/gestures/#viewport-options

            <LevelsWrapper
                key={index}
                initial="hidden"
                whileInView="show"
                variants={container}
                viewport={{ once: true, amount: 0.8, margin: "200px" }}
            >
于 2022-02-14T15:18:00.990 回答