最稳妥的检测方式是判断 window.history 是否存在且 pushstate 为函数:if (window.history && typeof window.history.pushstate === 'function') { / 可用 / } else { / 降级 / },避免仅检查 history 对象或使用 in 操作符。

HTML5 的跳转行为(比如 history.pushState、history.replaceState)在 IE9 及更早版本里根本不存在,强行调用会直接报错,而不是静默失败。 所以不能靠「写了就跑」,得先确认浏览器支不支持,再决定走 HTML5 跳转还是退回到 location.href 或哈希方案。
怎么检测 history.pushState 是否可用
最稳妥的方式是判断 history 对象是否存在且包含 pushState 方法:
if (window.history && typeof window.history.pushState === 'function') {
// 可安全使用 pushState
} else {
// 降级:改用 location.href 或 hashchange
}
注意别只检查 window.history——IE9 有 history 对象但没有 pushState;也别用 in 操作符(如 'pushState' in history),某些老版 Android 浏览器会返回 true 但实际调用就崩。
降级到哈希跳转时要注意 URL 同步和事件监听
当 pushState 不可用,常见做法是把路径写进 location.hash,再监听 hashchange 事件响应跳转。但这里有几个坑:
立即学习“前端免费学习笔记(深入)”;
-
hashchange在 IE8/9 中只支持通过attachEvent绑定,不能用addEventListener - 首次进入页面时,
hashchange不会触发,得手动读取location.hash并初始化视图 - 哈希值里的特殊字符(如
/、?)必须encodeURIComponent编码,否则可能被截断或解析异常 - 不要直接改
location.hash = '/user/123',应统一走封装函数,避免重复触发或状态不一致
服务端要不要适配?关键看是否开启 HTML5 History 模式
如果你在单页应用中用了 pushState 跳转,又没配服务端 fallback(比如 Vue Router 的 mode: 'history'),用户刷新页面就会 404——但这和老浏览器兼容性无关,而是部署问题。
真正影响老浏览器的是:你是否让它们也访问了「无后缀的纯路径」。例如,/user/123 这个地址在 IE9 下无法通过 pushState 激活,但如果服务端没配置,它连这个 URL 都打不开。所以:
- 老浏览器用户应始终走
hash模式(如/#/user/123),服务端只需托管根路径即可 - 如果坚持对所有用户都用 history 模式,就得确保服务端对所有前端路由返回同一份
index.html,且老浏览器能正确加载 JS 并接管路由 - 别指望
pushState降级后还能保持和服务端完全一致的 URL 结构——哈希模式本身就是妥协
最易被忽略的一点:replaceState 和 pushState 都会改变浏览器地址栏,但不会触发 popstate 事件;而用户点击后退按钮时才会触发。这意味着,你在降级方案里模拟「后退」逻辑时,不能只监听 popstate,还得在哈希变化时主动比对历史栈,否则 IE8 下后退会失灵。











