Next.js: Router.push('/link') не прокручивает верхнюю часть страницы при срабатывании

Созданный на 7 нояб. 2017  ·  25Комментарии  ·  Источник: vercel/next.js

Привет,

может быть, я что-то упускаю, но когда я использую эту функцию и перенаправляю на другую страницу, прокрутка не сбрасывается вверх, но страница загружается с прокруткой до середины, я знаю, почему эта проблема возникает, но могу ли я как-то исправить это с помощью какого-либо флага, например JAVASCRIPT Router.pusht({pathname: '/link', scrollreset: true}) или что-то в этом роде, в документации ничего похожего не нашел

Самый полезный комментарий

Я согласен, что должна быть опция scrollreset . Если вы не хотите делать это в componentDidMount , вы также можете сделать Router.push('/link').then(() => window.scrollTo(0, 0)); .

Все 25 Комментарий

должен ли он прокручиваться вверх или нет, решает пользователь. Я думаю, вы можете сделать это за componentDidMount

Я согласен, что должна быть опция scrollreset . Если вы не хотите делать это в componentDidMount , вы также можете сделать Router.push('/link').then(() => window.scrollTo(0, 0)); .

Router.push('/link').then(() => window.scrollTo(0, 0)); это правильный способ сделать это, не стесняйтесь добавить его в ридми @gragland ❤️

Спасибо @gralagland, ваше решение кажется не таким уродливым, но было бы неплохо иметь такую ​​возможность, чтобы сохранить принцип DRY. Единственное быстрое решение на данный момент - сделать живой шаблон, чтобы написать это 😅

Вау... Вы имеете в виду, что мне нужно просмотреть каждую страницу, чтобы добавить .then() ! Кстати, я использую next-routes , так что есть ли способ добавить это глобально, просто добавить этот код один раз, например, addRequestTransform , если вам нужно добавить некоторые заголовки перед вызовом API.

@MBach , вы также можете подключить window.scrollTo(0, 0) к componentDidMount целевого компонента.

Я просто хочу вмешаться и сказать, что нашел такое поведение крайне удивительным. Уже почти год создаю рабочие сайты с помощью Next.js и только сейчас обнаружил, что Router.push не возвращается в топ — я всегда думал, что Router.push ведет себя точно так же, как <Link> , но это был просто программный способ сделать это.

И с точки зрения соответствия поведения по умолчанию, такого как <a> против <Link> , не-SPA-эквивалент Router.push , похоже, устанавливает window.location , который также возвращает вам вверху страницы, нет? Для меня это имело бы больше смысла как поведение по умолчанию.

@gragland это не работает

Чтобы заставить его работать глобально, вы можете использовать встроенный прослушиватель событий маршрутизатора next.js: Router.events.on('routeChangeComplete', () => { window.scrollTo(0, 0); }); .
Просто поместите это в компонент, общий для всех страниц, например, в заголовок.

@timneutkens Есть ли причина, по которой поведение прокрутки по умолчанию для императива Router.push и <Link> отличается? Мне кажется очевидным багом то, что они ведут себя по-разному.

Router.back() не возвращает обещание, но имеет ту же проблему, что делать, вручную прокручивая вверх?

@alexsenichev Вы пробовали решение @macmenak ?

<Link href="/product/[id]" as={ /product/${item.id} } beforePopState={()=>{ window.screenTop = 0; }}> <a> <h6>{item.name}</h6> </a> </Link>

Привет. Почему у нас должна быть прокрутка по умолчанию для компонента Link до true , а для Router.push нет?

Я думаю, что этот вопрос должен быть пересмотрен.

Извините, но отметил участников: @liweinan0423 @timneutkens @exogen @goldenshun

Было бы неплохо, если бы в router.push() была опция для принудительной прокрутки вверх, но я не думаю, что она должна быть по умолчанию, поскольку это было бы критическим изменением для всех, кто уже предполагает, что это не так.

@markjackson02 markjackson02 Я не понимаю, как это может быть критическим изменением, поскольку браузер по умолчанию справился бы с этим. Я не согласен с тем, что у нас два разных подхода к одному и тому же функционалу.

Это определенно было бы переломным моментом. Люди создавали приложения такими, какие они есть сейчас, и ожидали, что они будут работать именно так.

Я не против того, чтобы они оба имели одинаковую функциональность по умолчанию, но я не думаю, что это стоит усилий по миграции.

В любом случае, эта проблема закрыта, поэтому мы должны открыть новую проблему, что бы мы ни хотели сделать.

@markjackson02 ОМХО, критическое изменение в том, что это еще не работает! Неправильное поведение уже сделано. Поэтому я думаю, что было бы неплохо поставить его так, как он должен. Но я согласен с вами, вкладчики, вероятно, не будут обращать на это внимание.

@Timer @timneutkens Кроме того, меня укусила разница в поведении Link и Router.push . FWIW, +1 к добавлению к options из Router.push , так как это сохранит обратную совместимость.

Вы можете использовать это для маршрутизации и прокрутки вверх страницы:

// route using nextjs router and scroll to the top of the page
const routeToTop = (router, ...args) => {
    if(typeof window !== 'undefined') window.scrollTo(0, 0)
    return router.push.apply(router, args)
}

// usage

const router = useRouter()

routeToTop(router, '/my/page')

routeToTop(router, '/articles/[slug]', `/articles/${article.slug}`)

routeToTop(router, {
    pathname: '/search',
    query: {q: searchQuery},
})

Кстати, это не так приятно для пользователя, как поведение Link , поскольку вы сразу прокручиваете страницу вверх, а не при загрузке следующей страницы.

Я добавил связанную проблему здесь для тех, кто заинтересован: https://github.com/vercel/next.js/issues/15206

FWIW, вот мой взгляд на обходной путь, которым поделились в связанной проблеме.

import { useRouter } from 'next/router';
import { useEffect } from 'react';

/**
 * React hook that forces a scroll reset to a particular set of coordinates in the document
 * after `next/router` finishes transitioning to a new page client side. It smoothly scrolls back to
 * the top by default.
 *
 * <strong i="6">@see</strong> https://github.com/vercel/next.js/issues/3249
 * <strong i="7">@see</strong> https://github.com/vercel/next.js/issues/15206
 * <strong i="8">@see</strong> https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions
 * <strong i="9">@param</strong> {ScrollOptions} [options={}] Hook options.
 * <strong i="10">@param</strong> {ScrollBehavior} [options.behavior='smooth'] Specifies whether the scrolling should animate smoothly,
 *  or happen instantly in a single jump.
 * <strong i="11">@param</strong> {number} [options.left=0] Specifies the number of pixels along the X axis to scroll the window.
 * <strong i="12">@param</strong> {number} [options.top=0] Specifies the number of pixels along the Y axis to scroll the window.
 */
function useRouterScroll({ behavior = 'smooth', left = 0, top = 0 } = {}) {
  const router = useRouter();
  useEffect(() => {
    // Scroll to given coordinates when router finishes navigating
    // This fixes an inconsistent behaviour between `<Link/>` and `next/router`
    // See https://github.com/vercel/next.js/issues/3249
    const handleRouteChangeComplete = () => {
      window.scrollTo({ top, left, behavior });
    };

    router.events.on('routeChangeComplete', handleRouteChangeComplete);

    // If the component is unmounted, unsubscribe from the event
    return () => {
      router.events.off('routeChangeComplete', handleRouteChangeComplete);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [behavior, left, top]);
}

export default useRouterScroll;

Используйте его где-нибудь в верхней части дерева компонентов (работает _app.js ).

// _app.js
function MyApp({ Component, pageProps }) {
  // Make sure pages scroll to the top after we navigate to them using `next/router`
  useRouterScroll();

  /* ... */
}

export default MyApp;

@nfantone когда эти поля меняются? behavior, left, top . Назад и вперед у меня не работает.

@rakeshshubhu Это влияет только на навигацию через next/router .

Вау... Вы имеете в виду, что мне нужно просмотреть каждую страницу, чтобы добавить .then() ! Кстати, я использую next-routes , так что есть ли способ добавить это глобально, просто добавить этот код один раз, например, addRequestTransform , если вам нужно добавить некоторые заголовки перед вызовом API.

Вам не нужно. Вместо этого я создаю один модуль и экспортирую его в те компоненты, которые в нем нуждаются. Поэтому, как только это нужно изменить, вы меняете это единственное место.

Также вы заметили, что я передаю маршрутизатор в качестве параметра, поскольку вы можете использовать только React Hooks, например, useRouter() внутри компонента.

export const navigate = (event, url, router) => {
  event.preventDefault();
  event.stopPropagation();

  // Force scrolling to top
  router.push(url).then(() => window.scrollTo(0, 0));
};
Была ли эта страница полезной?
0 / 5 - 0 рейтинги