Nuxt3中哈希变更时scrollBehavior未触发的问题排查与解决
问题
我有一个Nuxt3应用,通过插件修改scrollBehavior,插件文件为plugins/router.scrollBehavior.js,代码如下:
export default defineNuxtPlugin((nuxtApp) => { nuxtApp.$router.options.scrollBehavior = (to, from, savedPosition) => { console.log('scroll') if (savedPosition) return savedPosition if (from && from.path == to.path && to.hash) { const hash = to.hash.replace('#', '') const el = document.querySelector(`[id="${hash}"]`) if (!el) return if ('scrollBehavior' in document.documentElement.style) { return { left: 0, top: el.offsetTop - 100, behavior: 'smooth' } } else { return { left: 0, top: el.offsetTop - 100 } } } return { left: 0, top: 0, behaviour: 'smooth' } } })
页面包含多个带ID的锚点及对应的目录链接,链接使用<NuxtLink :to="{hash: '#id'}">。页面加载时scrollBehavior可正常触发(控制台能打印'scroll'),但点击目录链接或通过$router.push({ hash: '#id' })编程式跳转时,页面虽发生滚动,但scrollBehavior未被触发。请问这是什么原因?如何在同页面哈希变更时触发scrollBehavior?
原因
Vue Router(Nuxt3基于该路由库)默认仅在路径发生变化时触发scrollBehavior,当仅变更URL的哈希部分(同页面内锚点跳转)时,会直接使用浏览器原生锚点滚动逻辑,跳过自定义的scrollBehavior函数。
解决方法
方法1:通过Nuxt配置强制触发哈希变更时的scrollBehavior
在nuxt.config.ts中添加路由配置,让Vue Router在哈希变化时也执行自定义滚动逻辑:
export default defineNuxtConfig({ router: { options: { scrollBehaviorOptions: { hashMode: 'manual' // 关键配置:禁止浏览器原生哈希滚动,强制调用scrollBehavior } } } })
方法2:手动监听哈希变化执行滚动逻辑
如果方法1不生效,可以在插件中额外添加路由监听,手动处理同页面哈希跳转的滚动:
export default defineNuxtPlugin((nuxtApp) => { // 保留原有scrollBehavior配置 nuxtApp.$router.options.scrollBehavior = (to, from, savedPosition) => { console.log('scroll') if (savedPosition) return savedPosition if (from && from.path == to.path && to.hash) { const hash = to.hash.replace('#', '') const el = document.querySelector(`[id="${hash}"]`) if (!el) return const scrollOpt = { left: 0, top: el.offsetTop - 100 } if ('scrollBehavior' in document.documentElement.style) { scrollOpt.behavior = 'smooth' } return scrollOpt } return { left: 0, top: 0, behavior: 'smooth' } // 修正原代码拼写错误:behaviour → behavior } // 客户端环境下监听哈希变化,手动触发滚动 if (process.client) { nuxtApp.$router.afterEach((to, from) => { if (from.path === to.path && to.hash) { const hash = to.hash.replace('#', '') const el = document.querySelector(`[id="${hash}"]`) if (!el) return const offsetTop = el.offsetTop - 100 const scrollConf = { left: 0, top: offsetTop } if ('scrollBehavior' in document.documentElement.style) { scrollConf.behavior = 'smooth' } window.scrollTo(scrollConf) } }) } })
内容的提问来源于stack exchange,提问作者Cyril N.
相关产品推荐
相关产品推荐

