history.pushState()是浏览器原生支持的无刷新跳转核心方法,通过操作history对象新增历史记录、更新URL(同源相对或绝对路径),不触发重载;需配合popstate事件监听及手动内容加载实现完整SPA路由。
浏览器原生支持无刷新改变 URL 并记录历史,关键不是替换页面内容,而是操作 history 对象。直接调用 pushState() 即可新增一条历史记录,同时不触发页面重载。
它接受三个参数:state(任意可序列化对象)、title(目前多数浏览器忽略)、
url(相对路径或绝对路径,必须同源)。
url 必须与当前页面同源,跨域会抛出 SecurityError
state 会被存入历史栈,后续通过 popstate 事件读取,不能是函数或 DOM 节点fetch 或路由逻辑加载内容history.pushState({ page: 'detail', id: 123 }, '', '/item/123');
用户点击返回按钮或调用 history.back() 时,不会自动还原页面状态。你必须主动监听 popstate 事件,并根据 event.state 重新渲染。
pushState 和 replaceState 不会触发它event.state 就是之前传入 pushState() 或 replaceState() 的第一个参数popstate,需手动检查 history.state 初始化 UIwindow.addEventListener('popstate', (event) => {
if (event.state?.page === 'detail') {
loadItem(event.state.id);
}
});
当需要修改当前 URL 但不想让用户多按一次「后退」才能离开时,用 replaceState() 替代 pushState()。
立即学习“Java免费学习笔记(深入)”;
state 和 url
pushState() 参数完全一致,只是语义不同// 比如搜索关键词变更,不希望每次输入都生成一条历史
history.replaceState({ q: 'react' }, '', '/search?q=react');
使用 pushState() 需确保服务端支持:所有前端路由路径都应返回同一份 HTML(否则刷新会 404)。若无法控制服务端,可用 hash 模式降级,但它是另一套机制。
location.hash = '#/user' 不触发页面刷新,也不走 pushState 流程,监听的是 hashchange 事件hash 改变不会被计入 history.state,popstate 也不会触发pushState() 改变的是 URL 的 path 部分,hash 改变的是 fragment,二者互不影响真正做 SPA 路由时,别混用两种模式;服务端可配置就优先用 HTML5 模式,更干净也利于 SEO。