别再懵了!从小白到前端大厂选手的 History 路由通关指南(还顺带干翻 Hash)

pushState 一推,URL 改了;popstate 一监听,路由就跳了。原来不用刷新也能换页面,我真是学疯了!


👋 前言:小白一枚,但我有个「大厂梦」

作为一个正学 JavaScript 的小白,每次打开 B 站/掘金,看那些大佬用 React写路由跳转,URL 变了,页面内容也变了,但页面竟然没刷新?

我当时直接惊了:这不是魔法吗!?

后来我才知道,这背后其实是前端路由的秘密武器 ------ History 模式 SPA(Single Page Application)

今天我就来讲讲我对它的理解,既当学习笔记,也当成长记录。希望你也能和我一样,从小白慢慢走向大厂!


🧠 什么是 History 模式 SPA?

SPA,全称 Single Page Application,翻译成中文就是"单页应用"。

整个网站只用一个 HTML 页面,所有页面的内容都是通过 JavaScript 动态切换出来的,页面不刷新,体验丝滑到飞起!

而 History 模式,就是 SPA 中用来实现"URL 变化不刷页面"的一种技术方案,依靠的是浏览器提供的 History API,尤其是:

  • pushState()
  • replaceState()
  • popstate 事件

📍URL 变化的魔法就是这样来的!

以前你用 <a href="/about">,点击就会刷新整个页面 ------ 那是传统的多页应用(MPA)。

而使用了 History 模式的 SPA,页面不会刷新,URL 却能改变,给用户一种"好像真的跳了页面"的感觉,这种体验就是现代前端框架的底层魔法。


🧩 Hash 路由 vs History 路由,到底怎么选?

这里我还得给你补充点实用干货------Hash 路由和 History 路由的区别和适用场景。想学路由,这两个必须懂!

什么是 Hash 路由?

简单说,就是 URL 中用 #(井号)后面带路径,比如:

bash 复制代码
http://example.com/#/about

浏览器默认不会把 # 及后面的部分发送给服务器,也不会刷新页面。

Hash 路由优点:

  • 兼容性超好:支持所有浏览器,连 IE 都不怕
  • 部署简单:不用后端额外配置,服务器只管返回主页面即可
  • 简单粗暴:刷新页面不会 404

Hash 路由缺点:

  • URL 不够美观,带着丑丑的 #
  • SEO 不友好(虽然现在搜索引擎逐渐支持,但历史包袱仍在)

什么是 History 路由?

基于浏览器的 History API,URL 就像正常路径一样:

js 复制代码
http://example.com/about

路由跳转时,地址栏改变,但不会刷新页面。

History 路由优点:

  • URL 干净漂亮,符合正常网站路径习惯
  • 更符合 SEO,支持服务端渲染(SSR)
  • 更灵活,能自由控制浏览器历史栈

History 路由缺点:

  • 需要后端支持,配置服务器"所有路径都返回 index.html",否则刷新会 404
  • 兼容性比 Hash 略差,但主流现代浏览器都支持了

总结对比

  • 兼容性:Hash 路由 > History 路由
  • URL 美观度:History 路由 > Hash 路由
  • SEO 支持:History 路由 > Hash 路由
  • 部署复杂度:Hash 路由 < History 路由

💡 核心知识点全解析

✅ 1. history.pushState()

这是修改地址栏但不刷新页面的关键 API。

js 复制代码
history.pushState({ page: 'about' }, '', '/about');

含义很简单:

  • 改变 URL:地址栏变成了 /about
  • 页面不会刷新(JavaScript 控制渲染)
  • 浏览器历史记录多了一条(用户可以点"返回"回去)

✅ 2. history.replaceState()

pushState 类似,也是改 URL,但不会新增历史记录,而是替换当前记录

js 复制代码
history.replaceState({ page: 'home' }, '', '/home');

什么时候用?

  • 登录成功后不想让用户点击"返回"退回登录页;
  • 删除 URL 上的一次性参数,比如 /dashboard?token=123
  • 页面初始化时设置路径,但不希望用户能"返回"到空白页。

✅ 3. popstate 事件

这个事件会在你点击浏览器的"返回"或"前进"按钮时触发,或者你调用 history.back() / forward()

js 复制代码
window.addEventListener('popstate', (event) => {
  console.log('popstate 触发了,状态是:', event.state);
});

它的作用就是:让你有机会在用户返回/前进时更新页面内容!

结合 event.state(就是你之前 pushState 时传进去的状态),你就能知道现在要显示哪一页内容啦!


🛠 手把手写一个迷你 SPA 路由器

终于到了实践环节,来点硬核干货!

js 复制代码
<!-- index.html -->
<button id="home">Home</button>
<button id="about">About</button>
<div id="view"></div>

<script>
  const view = document.getElementById('view');

  function render(path) {
    if (path === '/about') {
      view.innerHTML = '<h2>这是关于页</h2>';
    } else {
      view.innerHTML = '<h2>这是首页</h2>';
    }
  }

  document.getElementById('home').addEventListener('click', () => {
    history.pushState({ path: '/' }, '', '/');
    render('/');
  });

  document.getElementById('about').addEventListener('click', () => {
    history.pushState({ path: '/about' }, '', '/about');
    render('/about');
  });

  // 初始化加载
  render(location.pathname);

  // 监听返回/前进按钮
  window.addEventListener('popstate', (event) => {
    const path = event.state?.path || location.pathname;
    render(path);
  });
</script>

它做了什么?

  • 点击按钮不刷新页面,地址栏 URL 改变了;
  • 页面内容手动更新;
  • 点击浏览器"后退"按钮,页面内容也会同步回退!

这就是真·手写路由的第一步!是不是觉得也没那么难?


🧠 History 模式 SPA 的优缺点

既然它这么厉害,那有没有坑呢?当然有!

✅ 优点:

  • URL 美观:没有 #,直接 /about /user/123
  • 更符合用户习惯:用户可以收藏、分享、前进后退
  • 支持 SEO(配合 SSR 服务端渲染)

❌ 缺点:

  • 需要后端配合部署!

    • 如果用户刷新 /about 页面,服务器会直接找 /about 路径,如果没有配置,会返回 404!
    • 需要配置:所有路径都 fallback 到 index.html

📦 解决方式(以 nginx 为例):

nginx 复制代码
location / {
  try_files $uri /index.html;
}

✅ 总结:这是 SPA 的核心,也是通往大厂的第一道门

如果你正在学前端、追求更高的技术深度、希望进大厂,那理解 History 模式的 SPA 路由机制是你必须迈过的一道门槛!

本篇你已经学会了:

  • 什么是 SPA?什么是 History 模式?
  • Hash 路由和 History 路由的区别和适用场景
  • pushStatereplaceState 的区别
  • popstate 监听返回跳转
  • 如何手写一个简单的前端路由
  • History 模式的优缺点与部署注意事项

🚀 写在最后:我不再是只会写 alert() 的人了!

当我第一次点击"关于"页面,看到地址栏悄咪咪地变成 /about,页面跟着变了,但没有刷新......那一刻我知道,我已经不再是那个只会写 alert('hello world') 的小白了!

这只是前端成长之路上的一小步,但你、我、我们都在路上。


如果这篇文章有帮到你,记得点赞 👍 收藏 ⭐ 留言 ✍️ 一波!

相关推荐
ZzMemory4 分钟前
深入理解JS(八):事件循环,单线程的“一心多用”
前端·javascript·面试
汪子熙3 小时前
浏览器环境中 window.eval(vOnInit); // csp-ignore-legacy-api 的技术解析与实践意义
前端·javascript
BUG收容所所长3 小时前
🤖 零基础构建本地AI对话机器人:Ollama+React实战指南
前端·javascript·llm
小高0073 小时前
🚀前端异步编程:Promise vs Async/Await,实战对比与应用
前端·javascript·面试
Spider_Man3 小时前
"压"你没商量:性能优化的隐藏彩蛋
javascript·性能优化·node.js
用户87612829073743 小时前
对于通用组件如何获取表单输入,区分表单类型的试验
前端·javascript
Bdygsl4 小时前
前端开发:JavaScript(6)—— 对象
开发语言·javascript·ecmascript
Mintopia5 小时前
AIGC Claude(Anthropic)接入与应用实战:从字节流到智能交互的奇妙旅程
前端·javascript·aigc
Mintopia5 小时前
Next.js 样式魔法指南:CSS Modules 与 Tailwind CSS 实战
前端·javascript·next.js
kfepiza5 小时前
JavaScript的 async , await 笔记250808
javascript