Привет,
может быть, я что-то упускаю, но когда я использую эту функцию и перенаправляю на другую страницу, прокрутка не сбрасывается вверх, но страница загружается с прокруткой до середины, я знаю, почему эта проблема возникает, но могу ли я как-то исправить это с помощью какого-либо флага, например JAVASCRIPT Router.pusht({pathname: '/link', scrollreset: true})
или что-то в этом роде, в документации ничего похожего не нашел
должен ли он прокручиваться вверх или нет, решает пользователь. Я думаю, вы можете сделать это за 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));
};
Самый полезный комментарий
Я согласен, что должна быть опция
scrollreset
. Если вы не хотите делать это вcomponentDidMount
, вы также можете сделатьRouter.push('/link').then(() => window.scrollTo(0, 0));
.