window.history.pushstate 可在不刷新页面下更新 url 并保存状态,是 spa 路由核心;需配合 popstate 事件响应导航,并服务端 fallback + 前端初始化处理直接访问。

使用 window.history.pushState 可以在不刷新页面的前提下更新浏览器地址栏 URL,同时保留当前页面状态,是构建单页应用(SPA)路由的核心手段之一。关键在于它只改 URL 和历史记录,不触发页面跳转或重新加载。
pushState 的基本用法和参数含义
pushState 接收三个参数:state 对象、标题(通常忽略)、新的 URL 路径。实际中标题参数基本不生效(多数浏览器会忽略),重点是 state 和 URL:
-
state:一个可被序列化的 JavaScript 对象,会在后续的
popstate事件中还原,用于保存路由相关数据(如页面类型、ID、搜索参数等) -
URL:相对路径(如
/user/123)或绝对路径(需同源),不能跨域;浏览器地址栏会更新,但不会发起请求
示例:
window.history.pushState({ page: 'user', id: 123 }, '', '/user/123');配合 popstate 实现前进后退的响应
仅调用 pushState 不够——用户点击浏览器“后退”按钮时,页面不会自动切换内容。必须监听 popstate 事件,并根据 event.state 渲染对应视图:
- 该事件在用户点击前进/后退、或通过
history.back()/history.forward()触发时触发 - event.state 就是之前传入
pushState的那个对象,可用于判断目标页面 - 注意:初始页面加载(非导航触发)不会触发 popstate,首次进入需手动初始化视图
常见写法:
window.addEventListener('popstate', (e) => {if (e.state?.page === 'user') renderUserPage(e.state.id);
else if (e.state?.page === 'home') renderHomePage();
});
处理直接访问 URL 或刷新页面的情况
pushState 不影响服务端,所以用户直接输入 /user/123 或刷新页面时,浏览器会向服务器发起真实请求。为避免 404,需做两件事:
-
服务端配置 fallback:将所有前端路由路径(如
/user/*)都返回主 HTML 文件(如index.html),让前端 JS 接管渲染 -
前端启动时读取当前 URL:在 JS 初始化阶段解析
location.pathname,主动调用渲染逻辑(不要依赖 popstate)
例如,在入口脚本中:
const path = location.pathname;if (path.startsWith('/user/')) {
const id = path.split('/')[2];
renderUserPage(id);
}
注意事项与实用技巧
- URL 必须同源,否则抛出安全错误
- state 对象大小受限(Chrome 约 640KB),不宜存大量数据,建议只存关键标识
- 可结合
history.replaceState替换当前历史项(适合表单提交后清除参数等场景) - 调试时可用
history.state查看当前项的 state,用history.length检查历史栈长度 - 避免在 pushState 后立即修改 document.title —— 部分浏览器可能不更新,应统一在 popstate 处理逻辑中设置











