Next.js 中的自定义页面/路由转换 主要问题当前实施

问题描述

我正在尝试使用 Next.js 的框架和 Greensock 动画库(如果适用)实现基于回调的路由转换。例如,当我从主页开始然后导航到 /about 时,我希望能够执行以下操作:

HomepageComponent.transitionOut(() => router.push('/about'))

理想情况下,在推送状态之前通过像中间件之类的东西一样监听路由器

Router.events.on('push',(newUrl) => { currentPage.transitionOut().then(() => router.push(newUrl)) });

主要问题

主要问题是我还有一个后台运行的 WebGL 应用程序,与 React 生态系统分离(因为它使用 requestAnimationFrame)。所以我想要基于回调的转换的原因是因为我需要在 WebGL 转换完成后运行它们。

当前实施

我研究过使用 React Transition Group 并且看到了 docs for the Router object,但似乎都不是基于回调的。换句话说,当我转换到一个页面时,WebGL 和页面转换同时运行。而且我不想做一个笨拙的解决方案,比如为页面转换添加延迟,以便它们发生在 WebGL 转换之后。

这就是我现在所拥有的:

app.js

<TransitionGroup>
  <Transition
    timeout={{ enter: 2000,exit: 2000 }}
    // unmountOnExit={true}
    onEnter={(node) => {
      gsap.fromTo(node,{ opacity: 0 },{ opacity: 1,duration: 1 });
    }}
    onExit={(node) => {
      gsap.to(node,{ opacity: 0,duration: 1 });
    }}
    key={router.route}
  >
    <Component {...pageProps}></Component>
  </Transition>
</TransitionGroup>

webgl 部分

Router.events.on('routeChangeStart',(url) => {
  // transition webGL elements

  // ideally would transition webGL elements and then allow callback to transition out html elements
});

我还尝试使用 eventemitter3 库来执行以下操作:

// a tag element click handler
onClick(e,href) {
  e.preventDefault();
  this.transitionOut().then(() => { Emitter.emit('push',href); });
  // then we listen to Emitter 'push' event and that's when we Router.push(href)
}

然而,这种方法在使用后退/前进按钮进行导航时遇到了巨大的问题

解决方法

这有点晚了,但我今天自己也在研究这个。为此使用 Framer Motion 真的很容易,但我也想使用 GSAP/React Transition Group。

对于 Framer Motion,我只是用一个运动组件包裹了 Next :

  <motion.div
    key={router.asPath}
    initial={{ opacity: 0 }}
    animate={{ opacity: 1 }}
    exit={{ opacity: 0 }}
  >
    <Component {...pageProps} />
  </motion.div>

对于 GSAP / React Transition Group,不确定这是否是正确的方法,但它按我的预期工作(见评论):

  const [state,setstate] = useState(router.asPath) // I set the current asPath as the state

  useEffect(() => {
  const handleStart = () => {
    setstate(router.asPath) // then on a router change,I'm setting the state again
    // other handleStart logic goes here 
  }
  const handleStop = () => {
    ... // handleStop logic goes here
  }

  router.events.on("routeChangeStart",handleStart)
  router.events.on("routeChangeComplete",handleStop)
  router.events.on("routeChangeError",handleStop)

  return () => {
    router.events.off("routeChangeStart",handleStart)
    router.events.off("routeChangeComplete",handleStop)
    router.events.off("routeChangeError",handleStop)
  }
},[router])

  <Transition
    in={router.asPath !== state} // here I'm just checking if the state has changed,then triggering the animations
    onEnter={enter => gsap.set(enter,{ opacity: 0 })}
    onEntered={entered => gsap.to(entered,{ opacity: 1,duration: 0.3 })}
    onExit={exit => gsap.to(exit,{ opacity: 0,duration: 0.3 })}
    timeout={300}
    appear
  >
    <Component {...pageProps} />
  </Transition>