Как перемещаться и прокручиваться к элементу с идентификатором в следующем. js Страница, обернутая AnimatePresence - PullRequest
1 голос
/ 29 мая 2020

Я использую Framer Motion для анимации Next. js переходов между страницами. Однако использование использования AnimatePresence нарушает навигацию по ссылкам hash, и страница больше не переходит к целевому элементу id.

Переходы страниц идеальны, пока вы не захотите перейти к har sh 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;

Я ожидаю go прямо в раздел с id="the-team", но это не сработает. Refre sh страницы со ссылкой ha sh показывает, что изначально он находится в целевом элементе, но быстро переходит наверх. Это так быстро и легко пропустить. Как сохранить ли переходы между страницами, но все еще могу перейти к ha sh id?

1 Ответ

1 голос
/ 29 мая 2020

Виновник - это exitBeforeEnter опора на AnimatePresence. Удаление опоры исправляет навигацию ha sh id, но ломает некоторые из моих вариантов использования.

Если установлено значение true, AnimatePresence будет отображать только один компонент за раз. Выходящий компонент завершит sh свою анимацию выхода до того, как входящий компонент будет визуализирован. - framer-motion docs

Я не мог просто удалить опору exitBeforeEnter, так как я включил ее, чтобы исправить ошибку, которая у меня была при нацеливании узел на входящей странице столкнулся с идентичным узлом в старом экземпляре выходящей страницы. Например, ref logi c в анимированном заголовке svg на выходящей странице сталкивается с заголовком входящей страницы svg ref logi c.

Чтобы получить лучшее из обоих миров, используйте onExitComplete, что «Срабатывает, когда все выходящие узлы завершили анимацию», я передал ему обратный вызов, который проверяет ha sh из widow.location.hash и плавно прокручивает до идентификатора, используя scrollIntoView Примечание: onExitComplete действует, только если exitBeforeEnter prop равно 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;


Live CodeSandbox здесь .

PS : по какой-то причине window.location.hash в предварительном просмотре песочницы всегда является пустой строкой, нарушая навигацию ha sh, но открывая предварительный просмотр на отдельной вкладке браузера работает как оберег.

...