为何Chrome中禁用浏览器返回按钮代码需执行history.state才生效?
这事儿其实是浏览器历史栈的处理逻辑和你代码的监听事件匹配度问题,我给你一步步捋清楚:
1. 直接运行时失效的核心原因
你从Login.html跳转到Home.html后,页面加载时执行了history.pushState("anything", "", "#1"),理论上历史栈应该变成:
- 第0条:
Login.html - 第1条:
Home.html(初始跳转的条目) - 第2条:
Home.html#1(pushState添加的新条目)
但Chrome有个导航优化机制:如果页面刚完成跳转就立即执行pushState,浏览器可能会把初始跳转的Home.html和pushState生成的Home.html#1合并成一条历史记录。这时候历史栈就变成了[Login.html, Home.html#1],点击返回按钮自然直接回到Login.html,你的hashchange事件根本没机会触发(因为没有hash变化的过程)。
2. 控制台执行history.state后生效的原因
当你在控制台输入history.state并回车时,浏览器会强制确认当前的历史状态,相当于“刷新”了历史栈的记录,把之前合并的条目重新拆分成独立的两条:Home.html和Home.html#1。这时候历史栈恢复成正常的三条,点击返回按钮会先回到Home.html(无hash),此时hash从#1变为空,触发hashchange事件,你的代码把hash设为a,相当于在历史栈里又加了一条Home.html#a,这样再点击返回只会在Home.html#1和Home.html#a之间循环,不会回到Login.html。
3. 更靠谱的禁用返回按钮方案
你当前用hashchange事件的思路有局限性——它只在同一个页面的hash变化时触发,跨页面导航(比如回到Login)不会触发这个事件。更稳妥的方式是监听popstate事件(返回按钮本质上触发的是这个事件):
// 页面加载时先添加一条当前页面的状态记录 history.pushState(null, null, window.location.href); window.addEventListener('popstate', function(event) { // 每次点击返回,就再添加一条当前页面的状态记录,让历史栈停在当前页 history.pushState(null, null, window.location.href); });
这个方案不管是hash变化还是纯状态跳转,都能拦截返回操作,避免依赖hash的局限性。
内容的提问来源于stack exchange,提问作者Saksham Chaudhary

