React.Js + Framer Motion 仅在初始页面加载时设置动画

Kry*_*k21 7 animation reactjs framer-motion

我正在开发一个 React 项目,其中的组件在滚动查看时会显示动画。我正在使用 Framer Motion。我怎样才能使动画仅在您第一次滚动组件时触发?

现在,如果我向下滚动页面,动画就会按预期工作。但是,如果我刷新或离开页面并返回,动画将再次触发。滚动到页面中间,刷新,然后向上滚动将在之前滚动的组件上触发动画。

我知道这是 Framer Motion 在组件重新安装时从初始值到动画值的默认行为。我希望防止之前位于用户视口中的组件出现这种行为。

下面发布了其中一个组件的示例代码。任何帮助表示赞赏。

const Banner = ({ title, body, buttonStyle, buttonText, image, switchSide, link }) => {
  const { ref, inView } = useInView({
    threshold: .8
  })
  return (
    <motion.div className="banner" 
      ref={ref}
      initial={{  opacity: 0 }}
      animate={ inView ? {  opacity: 1 } : ''}
      transition={{ duration: .75 }}
    >
      <div className={`container ${switchSide ? 'banner-switch': ''}`}>
        <div className="side-a">
          <img src={ image } />
        </div>
        <div className="side-b">
          <h2>{ title }</h2>
          <p>{ body }</p>
          {
            buttonText
              ? <Button buttonStyle={buttonStyle} link={link} justify="flex-start">{ buttonText }</Button>
              : ''
          }
        </div>
      </div>
    </motion.div>
  )
}
export default Banner
Run Code Online (Sandbox Code Playgroud)

Mat*_*ony 12

Framer Motion 现在已内置对此的支持。查看此链接:

https://codesandbox.io/s/framer-motion-animate-in-view-5-3-94j13

相关代码:

function FadeInWhenVisible({ children }) {
  return (
    <motion.div
      initial="hidden"
      whileInView="visible"
      viewport={{ once: true }}
      transition={{ duration: 0.3 }}
      variants={{
        visible: { opacity: 1, scale: 1 },
        hidden: { opacity: 0, scale: 0 }
      }}
    >
      {children}
    </motion.div>
  );
}
Run Code Online (Sandbox Code Playgroud)

用法:

<FadeInWhenVisible>
  <Box />
</FadeInWhenVisible>
Run Code Online (Sandbox Code Playgroud)

这可确保当元素进入视口时动画仅发生一次。我们不再使用react-intersection-observer来检查元素是否在视口中!

  • 如果您使用反应路由器进入另一个页面并返回,这将不起作用。 (3认同)

ind*_*nin 8

我最近遇到了类似的问题。我正在实现介绍动画,并且不希望它在每次页面刷新时触发,因此我制作了一个自定义挂钩,该挂钩在本地存储中保存时间戳,并且在每个页面刷新时将保存的时间与存储的时间戳进行比较,并在时间过去时触发,在那里存储一个新值。如果您只想玩一次,您可以简单地实现自定义我的代码来存储布尔值,然后您\xe2\x80\x99就可以开始了。

\n

我的定制钩子

\n
import {useEffect} from \'react\';\n\nconst useIntro = () => {\n\nconst storage = window.localStorage;\nconst currTimestamp = Date.now();\nconst timestamp = JSON.parse(storage.getItem(\'timestamp\') || \'1000\');\n\nconst timeLimit = 3 * 60 * 60 * 1000; // 3 hours\n\nconst hasTimePassed = currTimestamp - timestamp > timeLimit;\n\nuseEffect(() => {\n    hasTimePassed ? \n        storage.setItem(\'timestamp\', currTimestamp.toString()) \n        : \n        storage.setItem(\'timestamp\', timestamp.toString());\n}, []);\n\nreturn hasTimePassed;\n};\n\nexport default useIntro;\n
Run Code Online (Sandbox Code Playgroud)\n

您需要在代码中进行这个简单的更改

\n

\r\n
\r\n
import {useEffect} from \'react\';\n\nconst useIntro = () => {\n\nconst storage = window.localStorage;\nconst currTimestamp = Date.now();\nconst timestamp = JSON.parse(storage.getItem(\'timestamp\') || \'1000\');\n\nconst timeLimit = 3 * 60 * 60 * 1000; // 3 hours\n\nconst hasTimePassed = currTimestamp - timestamp > timeLimit;\n\nuseEffect(() => {\n    hasTimePassed ? \n        storage.setItem(\'timestamp\', currTimestamp.toString()) \n        : \n        storage.setItem(\'timestamp\', timestamp.toString());\n}, []);\n\nreturn hasTimePassed;\n};\n\nexport default useIntro;\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

希望这就是您所追求的。

\n