hash 路由锚点
浏览器在通过 # 改变 url 的时候(比如 a 标签锚点),会不可避免(至少到本文时间 2023-07-21 是如此)地改变页面的滚动位置,没有办法可以阻止这个行为。即使通过监听 hashchange 来 preventDefault 事件也不会生效。
所幸,浏览器的 location 提供了 pushState 和 replaceState 方法,如果通过这两个方法改变 hash,是不会导致页面跳转的。(当然 history 对象也可以)
用例:
1 | location.pushState('', '', hashUrl) |
但如果使用这种方法,会导致 vue-router 无法监听到 route 的改动,所以这个属性也不会触发响应式的变化。
我发现 VuePress 内部实现了这样的改变 # 路由页面不滚动的方法,去翻看了一下源码,发现 Vue Router 中存在一个 scrollBehavior 的属性,允许自定义路由跳转时页面滚动的位置,或者是否触发。之后发现它可以返回一个 { el: hashName }
的对象用作滚动,我就知道这也是使用了 pushState ,移除了 # 的影响,之后再自己使用 window.ScrollTo
来做一个手动跳转。其实和我自己的实现是一致的,只是自己的实现无法告知 Vue Router。
另外尝试了一种办法:监听 hashchange
所有 # 路由不再特殊处理,只是在页面滚动时候。记录当前位置,在 hash 跳转的时候,页面已经做完滚动更新之后,再自己使用 scrollTo 跳转到之前记录的位置,从而看上去位置没有变化,但实际上这种方法页面会有一个一闪而过的效果,体验不是很好,就没有用上。