返回

如何在 Nuxt 3 中解决页面加载后触发滚动事件的问题?

vue.js

解决 Nuxt 3 scrollBehavior 页面加载后触发滚动事件

背景

在 Nuxt 3 项目中,使用 scrollBehavior 管理页面滚动时,可能遇到页面加载完成后触发滚动事件的问题。这会导致组件锚点滚动不准确,尤其是当页面包含依赖 API 请求加载的组件时。

问题分析

官方提供的 hooks.hook('page:finish', async () => {}) 钩子旨在等待页面完全加载,但实际上并不是最后一个被调用的。这是因为其他子组件中的其他钩子可能会在 page:finish 钩子之后被调用,导致时序问题。

解决方法:使用 watchEffect

为了在触发滚动事件之前检查父页面是否完全加载,可以使用 watchEffect 来监控 $nuxt.loading 状态。当 $nuxt.loading 变为 false 时,表示页面已完成加载,可以安全地触发滚动事件。

代码示例:

scrollBehavior (to, from, savedPosition) {
  const nuxtLoading = useNuxtApp().loading

  const scroll = async () => {
    if (nuxtLoading.value) {
      // 页面仍在加载中,等待加载完成
      await watchEffect((onInvalidate) => {
        watch($nuxt.loading, (val) => {
          if (!val) {
            // 页面已加载完成,触发滚动
            // ... 滚动逻辑 ...
            onInvalidate()
          }
        })
      })
    } else {
      // 页面已加载完成,触发滚动
      // ... 滚动逻辑 ...
    }
  }

  return scroll()
}

其他注意事项

  • 确保 API 请求在 mounted 钩子中发起,而不是 created 钩子中,因为 mounted 阶段组件已挂载到 DOM 中。
  • 如果页面使用动态路由,请确保在 page:start 钩子中加载 API 数据,因为该钩子在每次路由导航之前触发。

总结

使用 watchEffect 监听 $nuxt.loading 状态可以确保 scrollBehavior 只在父页面完全加载后触发,从而解决滚动事件在页面加载完成后触发的问题。

常见问题解答

  1. 为什么 page:finish 钩子不是最后一个被调用的?

    这是由于时序问题,其他子组件中的其他钩子可能会在 page:finish 钩子之后被调用。

  2. 为什么在 mounted 钩子中发起 API 请求很重要?

    因为 mounted 阶段组件已挂载到 DOM 中,可以安全地发起 API 请求。

  3. 动态路由情况下加载 API 数据的最佳实践是什么?

    在动态路由中,应在 page:start 钩子中加载 API 数据,因为该钩子在每次路由导航之前触发。

  4. 是否有其他解决此问题的替代方法?

    可以使用 nextTicksetTimeout 来延迟滚动事件,但这可能不是最优雅的解决方案。

  5. 此解决方法是否适用于所有情况?

    此解决方法适用于 Nuxt 3 中滚动事件在页面加载完成后触发的情况。然而,对于其他框架或特定的项目配置,可能需要进行调整。