7

我正在使用Framer MotionNext.js页面过渡设置动画。但是,使用使用AnimatePresence会破坏hash链接导航,并且页面不再转到目标id元素。

页面转换是完美的,直到您想要导航到页面上的苛刻 ID :(

// I have a link component setup like this
// index.tsx
<Link href="/about#the-team" scroll={false}>
  <a>The Team</a>
</Link>

// Targeting another page `about.tsx` with the id
// about.tsx

{/* ...many sections before.. */}
<section id="the-team">{content}</section>

我有一个_app.tsx如下所示的自定义。

// _app.tsx
import { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import { AnimatePresence } from 'framer-motion';

const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {
  const router = useRouter();
  return (
    <AnimatePresence exitBeforeEnter>
      <Component {...pageProps} key={router.route} />
    </AnimatePresence>
  );
};

export default MyApp;

我希望直接进入该部分,id="the-team"但它不起作用。使用哈希链接刷新页面显示它最初位于目标元素但很快跳转到顶部。它是如此快速和容易错过。如何保留页面转换但仍然能够导航到哈希 id?

4

1 回答 1

6

罪魁祸首是exitBeforeEnter on 的道具AnimatePresence。删除道具修复了哈希 id 导航,但破坏了我的一些用例。

如果设置为 true,AnimatePresence一次只会渲染一个组件。退出组件将在渲染进入组件之前完成其退出动画。-成帧运动文档

我不能只删除exitBeforeEnter道具,因为我已经包含它来修复我在进入页面中定位节点与退出页面的旧实例中的相同节点发生冲突的错误。例如ref,退出页面中动画 svg 标题上的逻辑与进入页面的标题 svg ref 逻辑冲突。

为了两全其美,使用onExitComplete “当所有退出节点完成动画输出时触发”,我向它传递了一个回调,该回调检查从widow.location.hash和平滑滚动到 id 的散列,使用scrollIntoView 注意:onExitComplete仅在exitBeforeEnterprop 为时有效true.

// pages/_app.tsx
import { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import { AnimatePresence } from 'framer-motion';

// The handler to smoothly scroll the element into view
const handExitComplete = (): void => {
  if (typeof window !== 'undefined') {
    // Get the hash from the url
    const hashId = window.location.hash;

    if (hashId) {
      // Use the hash to find the first element with that id
      const element = document.querySelector(hashId);

      if (element) {
        // Smooth scroll to that elment
        element.scrollIntoView({
          behavior: 'smooth',
          block: 'start',
          inline: 'nearest',
        });
      }
    }
  }
};

const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {
  const router = useRouter();
  return (
    <AnimatePresence exitBeforeEnter onExitComplete={handExitComplete}>
      <Component {...pageProps} key={router.route} />
    </AnimatePresence>
  );
};

export default MyApp;


现场CodeSandbox 在这里

PS:由于某种原因,window.location.hash沙盒预览中的始终是一个空字符串,破坏了哈希导航,但在单独的浏览器选项卡中打开预览就像一个魅力。

于 2020-05-29T14:47:17.433 回答