【问题标题】:Have TimelineLite only play once on Gatsby site让 TimelineLite 在 Gatsby 网站上只播放一次
【发布时间】:2020-10-28 21:33:00
【问题描述】:

我在 Gatsby 网站上设置了 TimelineLite 时间线,以便在用户导航到页面时为我的 hero 部分设置动画。但是,如果用户单击指向当前页面的链接,即如果用户在主页上并单击指向主页的链接,则它正在重新加载页面并触发时间线再次运行。有没有办法确保我当前的链接在 Gatsby 中处于非活动状态?

Hero.tsx

import React, { useEffect, useRef, useState } from 'react';

import css from 'classnames';
import { ArrowButton } from 'components/arrow-button/ArrowButton';
import { HeadingReveal } from 'components/heading-reveal/HeadingReveal';
import { gsap, Power2, TimelineLite } from 'gsap';
import { RichText } from 'prismic-reactjs';
import htmlSerializer from 'utils/htmlSerializer';
import { linkResolver } from 'utils/linkResolver';

import s from './Hero.scss';

gsap.registerPlugin(TimelineLite, Power2);

export const Hero = ({ slice }: any) => {
  const linkType = slice.primary.link._linkType;
  const buttonLink =
    linkType === 'Link.document' ? slice.primary.link._meta : slice.primary.link.url;

  const theme = slice.primary.theme;
  const image = slice.primary.image;

  const contentRef = useRef(null);
  const headingRef = useRef(null);
  const copyRef = useRef(null);
  const buttonRef = useRef(null);

  const [tl] = useState(new TimelineLite({ delay: 0.5 }));

  useEffect(() => {
    tl.to(contentRef.current, { css: { visibility: 'visible' }, duration: 0 })
      .from(headingRef.current, { y: 65, ease: Power2.easeOut, duration: 1 })
      .from(copyRef.current, { opacity: 0, y: 20, ease: Power2.easeOut, duration: 1 }, 0.5)
      .from(buttonRef.current, { opacity: 0, y: 10, ease: Power2.easeOut, duration: 1 }, 1);
  }, [tl]);

  return (
    <div
      className={css(s.hero, s[theme])}
      style={{
        background: image ? `url(${image.url})` : 'white',
      }}
    >
      <div className={s.hero__container}>
        <div className={s.content__left} ref={contentRef}>
          <HeadingReveal tag="h1" headingRef={headingRef}>
            {RichText.asText(slice.primary.heading)}
          </HeadingReveal>

          <div className={s.content__copy} ref={copyRef}>
            {RichText.render(slice.primary.copy, linkResolver, htmlSerializer)}
          </div>
          <div className={s.content__button} ref={buttonRef}>
            <ArrowButton href={buttonLink}>{slice.primary.button_label}</ArrowButton>
          </div>
        </div>
  
      </div>
    </div>
  );
};

【问题讨论】:

    标签: reactjs gatsby gsap reach-router


    【解决方案1】:

    如果您使用内置的&lt;Link&gt; 组件进行不应发生的导航,因为@reach/router 在同一页面上导航时不会触发并且不会重新呈现。那里没有任何补液。

    如果您使用的是锚点 (&lt;a&gt;),您将刷新整个页面,因此您的所有组件都将再次被触发。

    此外,在您的情况下,另一个可能解决问题的解决方法是使用带有空 deps ([]) 的 useEffect,创建 componentDidMount 效果。在这种情况下,由于页面没有重新加载,因此不会再次触发:

      const [tl] = useState(new TimelineLite({ delay: 0.5 }));
    
      useEffect(() => {
        tl.to(contentRef.current, { css: { visibility: 'visible' }, duration: 0 })
          .from(headingRef.current, { y: 65, ease: Power2.easeOut, duration: 1 })
          .from(copyRef.current, { opacity: 0, y: 20, ease: Power2.easeOut, duration: 1 }, 0.5)
          .from(buttonRef.current, { opacity: 0, y: 10, ease: Power2.easeOut, duration: 1 }, 1);
        return () => unmountFunction() // unmount to avoid infinite triggers
      }, []);
    

    注意:由于我不知道您的要求,您可能需要再做一些调整才能使代码正常工作。这个想法是删除t1的依赖来绕过这个问题。

    为避免无限触发,您可能还需要使用return () =&gt; unmountFunction() 卸载组件。

    【讨论】:

    • 谢谢,Ferran,您提供了很多答案!我正在使用内置的&lt;Link&gt; 组件,这让我有点困惑。明天我会试一试,并尝试更多地挖掘 &lt;Link&gt; 不起作用的原因。
    • 所以,问题似乎出在useEffect 它运行了多次。如果我从组件中删除时间线,则它不会重新加载。我尝试删除 tl 作为 useEffect 的依赖项,但它仍然在每次点击时运行代码。
    • 你好,费兰!所以,我仍然遇到同样的问题,甚至从依赖数组中删除 tl 也不起作用;它在每次点击时运行。您还有其他建议或资源需要我查看吗?
    • 我的猜测是卸载useEffect,但我不确定如何使用 GSAP 处理它。 github.com/hzdg/gsap-react-plugin/issues/6
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多