你好,
也许我遗漏了一些东西,但是当我使用此功能并重定向到另一个页面时,滚动并没有重置到顶部,而是页面加载滚动到中间,我知道为什么会发生这个问题,但是我可以用一些像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)
挂在 traget 组件的componentDidMount
上。
我只是想插话说我发现这种行为非常令人惊讶。 使用 Next.js 构建生产站点快一年了,直到现在才发现Router.push
并没有回到顶部——我一直认为Router.push
的行为与<Link>
完全一样
并且在匹配默认行为方面,如<a>
与<Link>
, Router.push
的非SPA等价物似乎正在设置window.location
,这也会返回您到页面顶部,不是吗? 作为我的默认行为,这将更有意义。
@gragland它不起作用
要使其在全球范围内工作,您可以使用内置的 next.js 路由器事件侦听器: Router.events.on('routeChangeComplete', () => { window.scrollTo(0, 0); });
。
只需将其放在所有页面共享的组件中,例如标题。
@timneutkens为什么命令式Router.push
和<Link>
的默认滚动行为不同是有原因的吗? 对我来说似乎是一个明显的错误,他们的行为不同。
Router.back() 不返回promise,但是有同样的问题,怎么办,手动向上滚动?
@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 OMHO,最大的变化是它还没有那样工作! 错误的行为已经发生。 所以我认为按照它应该的方式来表达是个好主意。 但我同意你的看法,贡献者可能不会在这里关注。
@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 :
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));
。