点击 href="#section2" 页面重载是因为 将其解析为 /myapp/#section2,触发完整导航;应使用 new url("#section2", document.baseuri).href 生成绝对 url 并配合 preventdefault() 拦截默认行为。

href="#section2" 点击后页面重载?base 正在劫持你的跳转
不是 JS 没绑事件,也不是浏览器 bug,而是 <base href="/myapp/"> 让浏览器把 href="#section2" 解析成 /myapp/#section2 —— 这个 URL 被当成新地址触发完整导航,导致页面刷新、滚动回顶。Network 面板里能看到一次对 /myapp/ 的 200 HTML 请求,就是证据。
用 new URL() 动态生成绝对片段链接
这是最干净、语义正确且兼容性好的方案:它绕过 base 对 hash 的拼接逻辑,直接返回当前页 URL 加上目标 hash。
-
new URL("#section2", document.baseURI).href返回的是类似https://example.com/myapp/page#section2的完整 URL,不会被 base 二次处理 - 适用于 React/Vue 中的动态属性:
href={new URL("#section2", document.baseURI).href} - 服务端渲染时也可用(需确保
document.baseURI可访问或降级为window.location.href) - 别手拼字符串如
window.location.pathname + "#section2",它仍可能被 base 解析为相对路径(尤其在 history 模式下 pathname 不含 hash 时)
必须配合 event.preventDefault() 才能真正拦截默认行为
即使 href 是绝对 URL,只要没显式阻止,默认跳转仍会触发路由重载或滚动重置——尤其在 SPA 中,hashchange 事件可能晚于 DOM 渲染,导致 scrollIntoView 失效。
- 原生写法:
@#@#@#@#@#@#@#@#@#@0 - Vue 中推荐用
@click.prevent+ref或document.getElementById - React 中用
onClick={(e) => { e.preventDefault(); ... }},避免依赖useEffect监听location.hash(首次加载带 hash 时易错过时机) - 注意:仅靠
href="javascript:void(0)"会丧失语义和键盘可访问性,不推荐作为锚点方案
首次加载带 hash 时,滚动定位容易失效
SPA 路由初始化常早于 DOM 渲染完成,location.hash 存在但目标元素还没挂载,scrollIntoView 找不到节点。
- 不要只在路由守卫或
mounted里检查location.hash,要加防抖或requestIdleCallback等待 DOM 就绪 - 更稳妥的做法是监听
DOMContentLoaded后再执行一次定位,或使用MutationObserver监控目标元素插入 -
scroll-margin-top必须加在目标元素自身上(不是父容器),且仅在 Chrome/Firefox 支持;Safari 需 fallback 到 JS 偏移计算
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











