正确写法是window.addEventListener('hashchange', handler),禁用onhashchange属性;首次加载需手动处理location.hash;回调内同步读取location.hash安全,异步读取可能出错;兼容IE8+,但需preventDefault避免空锚点滚动;移除监听必须用相同函数引用。

监听 hashchange 事件的正确写法
直接用 window.addEventListener('hashchange', handler),别用 onhashchange 属性赋值——后者容易被覆盖,且无法移除监听器。
注意:该事件只在 URL 的 # 后部分变化时触发(比如从 #/home 变成 #/about),不包括页面首次加载时的初始 hash 值。首次 hash 需要手动读取 location.hash 判断。
为什么 location.hash 有时读不到最新值?
在 hashchange 回调里直接读 location.hash 是安全的,但要注意:事件触发时机是 hash 已更新之后,所以值一定是最新的;不过如果回调里有异步操作(比如 setTimeout 或 Promise.then),再读 location.hash 就可能被后续跳转覆盖。
- ✅ 正确:
function handler() { console.log(location.hash); } - ❌ 危险:
function handler() { setTimeout(() => console.log(location.hash), 0); }—— 可能输出错误 hash
兼容性与路由场景下的典型陷阱
hashchange 在 IE8+、所有现代浏览器都支持,但有个隐蔽问题:当用户点击带 href="#xxx" 的链接时,若页面内没有对应 id="xxx" 的元素,浏览器仍会触发 hashchange,但同时也会滚动到页面顶部(document.body),干扰单页路由体验。
立即学习“前端免费学习笔记(深入)”;
- 避免空锚点:给所有
href="#xxx"链接加event.preventDefault(),或确保对应id存在 - SPA 路由中,建议统一用
history.pushState替代 hash(除非必须兼容老 IE) - Vue Router / React Router 默认用 history 模式,
hashchange仅用于 fallback 场景,别混用
移除监听器时必须传相同函数引用
用 addEventListener 添加的监听器,必须用 removeEventListener 配对移除,且函数引用要完全一致。匿名函数无法移除,会导致内存泄漏。
- ❌ 错误写法:
window.addEventListener('hashchange', () => {...}); window.removeEventListener('hashchange', () => {...});—— 两个箭头函数不是同一个引用 - ✅ 正确写法:
const handler = () => {...}; window.addEventListener('hashchange', handler); window.removeEventListener('hashchange', handler);
实际项目里,hash 路由逻辑往往耦合在组件生命周期中,容易漏掉移除。尤其在 React useEffect 或 Vue onUnmounted 里,务必检查 handler 是否稳定。



















