Next.js: Router.push('/link') 触发时不滚动页面顶部

创建于 2017-11-07  ·  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)挂在 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组件默认滚动到顶部trueRouter.push不是?

我认为这个问题应该重新审视。

抱歉,请标记贡献者: @liweinan0423 @timneutkens @exogen @goldenshun

如果router.push()上有一个选项可以强制滚动到顶部,那就太好了,但我认为它不应该是默认设置,因为对于已经假设它不这样做的每个人来说,这将是一个突破性的变化。

@markjackson02我看不出这将是一个重大变化,因为这是浏览器处理此问题的默认方式。 我不同意我们对相同的功能有两种不同的方法。

这绝对是一个突破性的变化。 人们一直在以现在的方式构建应用程序,并期望它能够以这种方式运行。

我并不反对它们都具有相同的默认功能,但我认为迁移工作不值得。

不管怎样,这个问题已经结束了,所以我们应该打开一个新的问题来做任何我们想做的事情。

@markjackson02 OMHO,最大的变化是它还没有那样工作! 错误的行为已经发生。 所以我认为按照它应该的方式来表达是个好主意。 但我同意你的看法,贡献者可能不会在这里关注。

@Timer @timneutkens另外,被LinkRouter.push行为差异所困扰。 FWIW,+1 添加到optionsRouter.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));
};
此页面是否有帮助?
0 / 5 - 0 等级

相关问题

timneutkens picture timneutkens  ·  250评论

Knaackee picture Knaackee  ·  122评论

Timer picture Timer  ·  87评论

Timer picture Timer  ·  90评论

acanimal picture acanimal  ·  74评论