让TimelineLite在Gatsby网站上只播放一次

问题描述

我在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,duration: 1 },0.5)
      .from(buttonRef.current,y: 10,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>
  );
};

解决方法

如果您正在使用内置的<Link>组件进行不应进行的导航,因为在同一页面上导航时@reach/router不会触发并且不会重新呈现。那里没有补水。

如果您使用锚点(<a>),则将刷新整个页面,以便再次触发所有组件。

此外,您可能会遇到麻烦的另一种解决方法是,使用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,duration: 1 },0.5)
      .from(buttonRef.current,y: 10,1);
    return () => unmountFunction() // unmount to avoid infinite triggers
  },[]);

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

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