在Nuxt JS中路由改变时页面无法滚动到顶部

4

我想在使用Nuxt进行路由切换时,始终回到页面顶部。

因此,我将其放入了我的app/router.scrollBehavior.js文件中:

export default function (to, from, savedPosition) {
  return { x: 0, y: 0 }
}

但它总是返回到上次保存的位置(在我的控制台中始终为null)。

你们有什么想法,我可能漏掉了什么?


1
谢谢@kissu,但不需要。我想要完全相反的行为:始终向上滚动,或者更好的是(可能带有过渡效果),始终到达页面顶部而无需滚动。 - davidgourdet
嗨@kissu,我还没有,但我现在会去做,并在那之后给你我的反馈。谢谢链接 :) - davidgourdet
@kissu 抱歉,这并没有帮助到我。我尝试了所有的解决方案,但都没有起作用。 - davidgourdet
1
是的,我正在考虑创建一个 CodeSandbox,也许在这个过程中我会理解一些重要的东西 :) - davidgourdet
@kissu 好的...在我的最小演示中:https://codesandbox.io/s/mystifying-bush-l2v6z, 一切都按预期工作(除了似乎这是Nuxt的默认行为,始终返回到顶部当路由改变时)。 所以也许我有一些阻止这种自然行为的东西。也许是一个在路由改变时没有被销毁的GSAP时间轴。我会进一步检查这个问题。 - davidgourdet
显示剩余10条评论
10个回答

14

对于 Nuxt v3.0.0-rc.3 版本:

middleware/ 文件夹中创建名为 route.global.ts 的文件。

然后在文件中编写以下内容:

export default defineNuxtRouteMiddleware((to, from) => {
  if (to.path !== from.path && process.client) {
    window.scrollTo(0, 0)
  }
})

仍在RC12上工作,记录一下。 - mcont

11
我使用 Nuxt 3(npm:nuxt3@3.0.0-rc.4-27588443.cf25525),但是没有一个解决方案适用于我。 最终,以下方法有效: /plugins/scrollToTop.js (任何文件名都可以,只需将其放入 plugins 文件夹中)。
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.$router.options.scrollBehavior = async (to, from, savedPosition) => {
    if (to.path !== from.path && process.client) {
      window.scrollTo(0, 0);
    }
  };
});

3

对于Nuxt 3

我的解决方案是在middleware文件夹中创建一个具有以下结构的文件:

export default defineNuxtRouteMiddleware((to, from) => {
  useNuxtApp().hook("page:finish", () => {
    if (history.state.scroll) {
      setTimeout(() => window.scrollTo(history.state.scroll), 0);
    } else {
      setTimeout(() => window.scrollTo(0, 0), 0);
    }
  });
})

我把它命名为fix-scroll-position.global.ts

使用setTimeout可以避免奇怪的跳转到顶部,这意味着用户不会看到页面向顶部滚动。

这段代码片段确保在路由更改时页面滚动到顶部,并且在单击后退按钮时保留滚动位置。最后一个功能是使用history.state.scroll实现的,它检查是否保存了来自先前路由的滚动位置。


请注意,以下内容适用于Nuxt3。 - kissu

2

谢谢 @Cianekjr,我在问题中忘记了“router.”这部分。实际上这是我命名的方式,所以我的问题还是一样的。 - davidgourdet

2
最终,GSAP 与 OP 的滚动行为发生冲突。
移除它后,解决了所有与 Nuxt 相关的问题,实际上 router.scrollBehavior.js 文件没有任何问题。

你如何确定这是否是@kissu的情况? - Boris Kamp
@BorisKamp 在 OP 的情况下,这就是问题所在。如果你想看看在你的情况下是否相同,你可以尝试从你的项目中删除它!我的意思是,或者任何可能与某些滚动交互的默认行为冲突的内容。 - kissu

2
顶部答案不是正确的方法。
在“app”目录中创建名为“router.options.js”的文件。
// app/router.options.js
export default {
  scrollBehavior() {
    return { top: 0 }
  }
}

使用 TypeScript(推荐)

// app/router.options.ts
import type { RouterOptions } from '@nuxt/schema'

export default <RouterOptions> {
  scrollBehavior() {
    return { top: 0 }
  }
}

我不会说它是不正确的,它具有不同的目的,同时仍然很灵活(如果您不想在所有地方都使用该行为)。 它的范围较小,但它可以实现相同的结果。 - kissu
滚动行为可能会(实际上应该)发生变化,因为现在有点故障。正确配置滚动行为的方法是通过scrollBehavior配置。当滚动错误修复后,滚动将比使用中间件“技巧”更好看。 - Alexander Horner
我的意思是两种解决方案都可行,取决于您是想要完全全局还是在中间件中。感谢您的输入! - kissu
这个解决方案首先滚动到顶部,然后再更改路由。我认为 OP 所问的是要将路由更改为顶部,而不是先路由到顶部,然后再更改。 - Ricky-U
很遗憾,目前在nuxt中还无法实现这一点... 真糟糕。 - Alexander Horner

1

我没有足够的声望来发表评论,因此只能回答问题。这是一个简单的提示,但我认为它可能会有所帮助。

我也曾经遇到过这个问题,一直找不到解决方法,但最终我找到了罪魁祸首。我的布局看起来像这样

<template>

  <div id="page" class="flex flex-col h-screen overflow-scroll bg-white">
    <Navbar />

    <slot />

    <Footer />
  </div>
</template>
组件周围的div具有屏幕高度,页面内容在该div中滚动,但因此窗口始终位于顶部,当单击NuxtLink时不会看到任何滚动。
我使用nuxt 3.0.0,当让#page div随着内容增长(即删除h-screenoverflow-scroll tailwind类)时,它具有向上滚动的行为,即使没有上述解决方案。
因此,如果您在稳定的nuxt 3版本中遇到此问题,请检查您的html。

这作为答案完全没问题。 - kissu

0
我在Nuxt 3中做了这个来实现以下目标:
  1. 如果设置了保存的位置,始终滚动到该位置
  2. 如果存在哈希值,则滚动到该哈希值
  3. 如果前两个条件都不满足,则滚动到顶部

This code goes in app/router.options.ts

import type {
  RouterConfig
} from "nuxt/schema";

export default < RouterConfig > {
  scrollBehavior(to, from, savedPosition) {
    return savedPosition ?
      savedPosition :
      to.hash ?
      {
        el: to.hash
      } :
      {
        top: 0
      };
  },
};

Nuxt在内部使用Vue Router,因此您可以在这里查看详细信息https://router.vuejs.org/guide/advanced/scroll-behavior.html

0

当前的默认行为已经修复了这个问题,并且表现得就像本地链接更改一样。请删除任何自定义的scrollBehavior配置并更新到最新版本的Nuxt。


你可能应该编辑你的另一个答案,链接在这里:https://dev59.com/d8Lra4cB1Zd3GeqPPLFs#73893669 - kissu

0
Nuxt的默认滚动行为是平滑地滚动到顶部。但在我的情况下,这并不是我想要的。
我需要一个路由器,它在滚动时不使用平滑效果,而是在哈希之间使用平滑效果,并且遵守scrollMargin属性和滚动到保存位置的规则。
这是我对Nuxt3(3.6.1)的建议。

/app/router.options.js

const scrollToElement = (hashElement) => {
  const element = document.querySelector(hashElement);
  if (element) {
    let scrollMargin = 0 // default there is no scrollMargin
    // read elements scrollMargin if it has one in css
    const style = window.getComputedStyle(element); // Get all styles of an element
    if (style.scrollMarginTop) scrollMargin = parseInt(style.scrollMarginTop);
    window.scrollTo({ top: element.offsetTop - scrollMargin, behavior: "smooth" }); 
  }
};

export default {
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) window.scrollTo(savedPosition);
    else if (to.hash && from.path === to.path) {
      scrollToElement(to.hash);
    } else if (to.hash && from.path !== to.path) { // if hash is on a different page
      useNuxtApp().hook("page:transition:finish", () => {
        scrollToElement(to.hash);
      });
    }
    
    else if (to.path !== from.path){

      // Wait until the page is rendered
      // Otherwise it scrolls to top when the transition starts 
      // before the actually page is changed
      useNuxtApp().hook("page:transition:finish", () => {
        window.scrollTo(0, 0);
      });
    }
  },
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接