代码之家  ›  专栏  ›  技术社区  ›  Marya

如何防止useInView()和useScroll()帧器运动钩子同时启动?

  •  0
  • Marya  · 技术社区  · 11 月前

    所需动画行为的描述: 当截面的一部分在视口内时,我要设置动画的元素应该使用从其初始位置到最终位置的垂直移动(在这种情况下从y=300到y=50)进入视口。 然后,对于离开/退出动画,我希望它与滚动一起发生,元素应该向屏幕的右侧移动,完全离开视口。

    实际行为:

    动画的顺序是第一个 inView ,这是来自的元素 y=300 y=50 然后开始向右移动,直到它在向下滚动页面时从视图中消失,但它的工作方式是,当黑色背景部分进入视口时,紫色背景元素的位置从屏幕的右侧开始,在滚动时移动到左侧,并一直滚动到黑色背景部分的末尾

    以下是我的实现:

    import { motion, useInView, useScroll, useTransform } from "framer-motion";
    import { useRef } from "react";
    import { SectionHeading } from "../UI/Headings";
    import { Section } from "../UI/Section";
    
    export default function About() {
      const inViewRef = useRef();
      useInView(inViewRef, { margin: "-180px 0px", once: true });
    
      const scrollRef = useRef(null);
      const { scrollYProgress } = useScroll({ target: scrollRef});
      const x = useTransform(scrollYProgress, [0, 1], ["0", "120%"]);
    
      return (
        <Section ref={inViewRef} id="who-i-am" className="bg-black h-[150svh]">
            <motion.div className="h-[150svh]"
            initial={{y: 300, visibility: "hidden"}}
            whileInView={{ y: 50, visibility: "visible" }} 
            // because here the y=50, when the user scrolls to the end of the section 
            // (which is the black bg, th purple container will go exceeds the section end by 50px,
            // to go around this I had to add another 50px to the section height).
            transition={{ duration: 1.6, ease: "easeIn",  type:"spring" }}>
              <motion.div ref={scrollRef} style={{x}} className="bg-purple-500 sticky top-0">
              <SectionHeading>SECTION HEADING</SectionHeading>
              <p>
                Lorem ipsum dolor, sit amet consectetur adipisicing elit. Temporibus aliquam veniam non quod veritatis sed ex ipsam doloribus. Ratione est quae quo architecto. Labore, quisquam. Ipsam vitae libero veniam eius, pariatur magni perferendis, molestiae numquam, iure dolorum voluptatum nemo? Illum laudantium quae voluptatem reiciendis hic at aut quam ea error.
              </p>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Vitae recusandae atque quibusdam ipsa ab fugit minus, veritatis earum molestias repellat.
              </p>
              </motion.div>
            </motion.div>
        </Section>
      );
    }
    

    我试着玩 offset 选项: useScroll({ target: scrollRef, offset:["center center"]}) 为了严格控制其开始和结束时间,使其看起来根本没有滚动效果,还试图设置一个条件,使水平运动仅在inView之后发生:

    <motion.div ref={scrollRef} style={isInView ? { x } : {}} className="bg-purple-500 sticky top-0">
    
    1 回复  |  直到 11 月前
        1
  •  1
  •   autext    11 月前

    要实现所需的动画行为,可以使用以下组合 useInView useScroll Framer Motion的挂钩。以下是修改代码的方法:

    import { motion, useInView, useScroll, useTransform } from "framer-motion";
    import { useRef } from "react";
    import { SectionHeading } from "../UI/Headings";
    import { Section } from "../UI/Section";
    
    export default function About() {
      const inViewRef = useRef();
      const isInView = useInView(inViewRef, { margin: "-180px 0px", once: true });
    
      const scrollRef = useRef(null);
      const { scrollYProgress } = useScroll({ target: scrollRef });
      const x = useTransform(scrollYProgress, [0, 1], ["0%", "120%"]);
    
      return (
        <Section ref={inViewRef} id="who-i-am" className="bg-black h-[150svh]">
          <motion.div
            className="bg-purple-500 sticky top-0"
            initial={{ y: 300, visibility: "hidden" }}
            animate={isInView ? { y: 50, visibility: "visible" } : {}}
            transition={{ duration: 1.6, ease: "easeIn", type: "spring" }}
          >
            <motion.div ref={scrollRef} style={{ x }} className="h-[150svh]">
              <SectionHeading>SECTION HEADING</SectionHeading>
              <p>
                Lorem ipsum dolor, sit amet consectetur adipisicing elit. Temporibus
                aliquam veniam non quod veritatis sed ex ipsam doloribus. Ratione
                est quae quo architecto. Labore, quisquam. Ipsam vitae libero veniam
                eius, pariatur magni perferendis, molestiae numquam, iure dolorum
                voluptatum nemo? Illum laudantium quae voluptatem reiciendis hic at
                aut quam ea error.
              </p>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Vitae
                recusandae atque quibusdam ipsa ab fugit minus, veritatis earum
                molestias repellat.
              </p>
            </motion.div>
          </motion.div>
        </Section>
      );
    }
    

    以下是我的更改:

    1. 我移动了 motion.div 外面的紫色背景 动作.div 这有 scrollRef 这样,输入动画将独立于水平滚动动画而发生。
    2. 我用了 animate 紫色道具 动作.div 基于 isInView 价值。当元素在视图中时,它将设置动画 y: 50 visibility: "visible" 否则,它将保持其初始状态。
    3. 我移动了 h-[150svh] 类到内部 动作.div 这有 scrollRef 这确保了水平滚动动画发生在该部分的高度内。

    有了这些更改,动画的行为应该如下:

    1. 当该部分进入视口时,紫色背景元素将从垂直方向移动 y: 300 y: 50 根据指定的转换。
    2. 当有人向下滚动页面时,紫色背景元素将从 0% 120% 通过调整其宽度,有效地将其移出视口到右侧。
    3. 该部分的高度设置为 150svh ,这应该防止紫色背景元素在到达其最终位置时超过该部分的末端。

    这是我能想到的所有修改,如果它仍然不起作用,我无能为力