onhashchange 不能直接赋值给 window.onhashchange,应使用 addeventlistener 绑定并在 dom 加载后手动调用路由函数;需区分路由 hash(以/开头)与锚点跳转,并确保 handler 可重入。

onhashchange 不能直接赋值给 window.onhashchange
很多人写 window.onhashchange = function() {...},结果发现事件只触发一次或根本没反应。这是因为 onhashchange 是一个只读属性(在多数现代浏览器中),重复赋值会被忽略,且无法可靠监听多次变化。
正确做法是用 addEventListener 绑定:
- 必须在 DOM 加载完成后注册,比如放在
DOMContentLoaded回调里 - 避免使用
window.onhashchange = handler,它容易被后续代码覆盖 - 如果已存在其他监听器,
addEventListener不会冲突,而onhashchange会被直接替换
首次加载时 hashchange 不会触发,必须手动初始化
URL 是 https://site.com/#/user 直接打开,hashchange 事件根本不会响——浏览器认为这是初始状态,不是“变化”。所以页面一打开就是白屏,点链接才动,这是最常见现象。
解决方法很简单:在绑定监听后,立刻手动执行一次路由处理逻辑:
- 用
location.hash.slice(1) || '/'取出路径部分(去掉#) - 别用
location.hash.substr(0, 1),它取的是#,不是路径 - 把解析和渲染逻辑封装成独立函数(比如
router()),绑定完就调一次
location.hash 赋值方式影响历史记录和滚动行为
跳转时写 location.hash = '/about' 和 location.hash = '#/about' 效果一样,但前者更安全——浏览器会自动补 #,且不会因多写 # 导致双重编码或意外截断。
关键细节:
-
location.hash = ''会清空 hash 并强制滚动到页面顶部,要避免;改用location.hash = '#'更稳妥 - 用
location.hash赋值会新增一条 history 记录,用户点后退能回到上一个 hash 状态 - 不要混用
pushState,否则hashchange不会响应路径变化,路由逻辑就断了
如何区分路由 hash 和普通锚点跳转
页面里有 <div id="contact"></div>,点击 <a href="#contact"></a> 也会触发 hashchange,但你并不想渲染新视图。
守卫逻辑必不可少:
- 约定所有路由 hash 都以
/开头,如#/home、#/post/123 - 普通锚点用纯 ID,如
#top、#section2 - 在 handler 里加判断:
if (hash.startsWith('/')) { render(hash) } - 别给 DOM 元素设
id="home"这类名字,否则和路由冲突
真正容易被忽略的是:每次 hashchange 触发时,handler 必须可重入。不能在里面重复绑定事件、重复初始化全局状态,也不能无条件发起请求——用户手动改地址栏再回车,就会连续触发,不加防护很快内存泄漏或视图错乱。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











