《hash+history》你点“关于”,页面却没刷新?!——揭秘前端路由的“穿墙术”

"咦?我点了个'关于我们',浏览器地址栏变了,但页面居然没刷新?!" 如果你也有过类似疑问,恭喜你,今天我们来揭开前端路由中最神秘的"障眼法"------SPA 路由的历史魔法(history API


一切的起源:古老的 history 对象

早在 HTML5 之前,浏览器里就有个叫 window.history 的家伙,功能嘛......很单纯:

scss 复制代码
history.back();  // 回退
history.forward();  // 前进
history.go(-1);  // 后退一页

这就像浏览器的"时光机",你可以在历史中前后穿梭。但仅此而已,它不能 篡改地址,也不能让你"伪装"页面。


hash 路由:前端第一代"穿墙术"

然后前端老祖宗想出了个招儿:# 来假装路径变了

ruby 复制代码
// 网址长这样
https://example.com/#/about

并监听这个事件:

javascript 复制代码
window.addEventListener('hashchange', () => {
  console.log(location.hash); // #/about
});

只要 # 后面变了,前端就换个组件,页面不刷新。听起来很牛?但 hash 有 几个尴尬的问题

  • URL 丑:https://xxx.com/#/about,像不像锚点导航?
  • SEO 不友好:爬虫不看 # 后面的
  • 用户体验差:刷新页面,hash 前面全都跑后端入口去了

HTML5 的历史大跃进:pushState & replaceState

到了 HTML5,历史 API 终于升级了,给你直接"改地址"的权力,但页面不刷新!

lua 复制代码
history.pushState({path: '/about'}, '', '/about');
  • ✅ 地址栏变成 /about
  • ✅ 页面没刷新
  • ✅ 可以监听返回按钮

这就是现代 SPA(单页面应用)路由的核心机制!


来点实战:自己造个 SPA 路由

我们用最原始的 HTML+JS,手撸一个模拟 Vue/React 的路由系统

html 复制代码
<body>
  <h2>SPA路由模拟</h2>
  <button onclick="navigate('/home')">首页</button>
  <button onclick="navigate('/about')">关于</button>
  <button onclick="navigate('/contact')">联系</button>
  <button onclick="replace('/pay')">支付</button>
  <div id="view">当前视图</div>

  <script>
    function render(path) {
      document.getElementById('view').innerHTML = `当前视图: ${path}`;
    }

    function navigate(path) {
      history.pushState({ path }, '', path);
      render(path);
    }

    function replace(path) {
      history.replaceState({ path }, '', path);
      render(path);
    }

    window.addEventListener('popstate', (event) => {
      render(event.state?.path || location.pathname);
    });
  </script>
</body>

一步步解释下:

  1. 按钮点击 调用 navigate('/about')

    • 当你点击页面上的"关于"按钮时,浏览器会执行 navigate('/about') 这个函数。

    • 这个函数内部调用了 history.pushState({ path: '/about' }, '', '/about'),意思是:

      • 给浏览器历史记录里"添加一条新记录" ,这条记录的地址是 /about
      • 地址栏的 URL 变成了 /about,但浏览器页面并没有刷新(不会重新加载页面资源)。
    • 接着,函数调用了 render('/about'),它会把页面中显示内容的那个区域(id 是 viewdiv)更新成"当前视图:/about",就像你"跳转"到"关于"页面了。

  2. 点击浏览器返回按钮 触发 popstate

    • 当你点击浏览器的"后退"按钮时,浏览器会触发 popstate 事件。
    • 事件回调里的代码会读取当前历史记录的状态(即 event.state),如果有 path,就用这个路径重新调用 render() 函数。
    • 这样页面的显示内容会变回你之前访问过的那个页面,用户就感觉"真的回去了",虽然整个页面没有刷新。
    • 这个过程保证了用户用浏览器的前进后退按钮,也能正确看到对应的内容。
  3. replaceState vs pushState

    • pushState往浏览器历史记录栈中添加一条新记录,意味着你每次调用它,浏览器就像多加了一页历史,用户可以点击"后退"按钮逐条回去。
    • replaceState 则是 替换当前这条历史记录,不会新增,也就是说"历史记录不变长",用户按"返回"不会回到之前的那个地址。
    • 比如你登录成功后跳到支付页面,如果用 pushState,用户点"返回"会回到登录页;用 replaceState,就直接把登录页那条记录给替换掉了,防止用户回去重复登录。

这样讲解,既保留了你的步骤清晰,又加了细节和易懂的比喻。你觉得怎么样?需要我帮你做成掘金文章的小节格式吗?

整个套路像不像魔术?

  • 地址栏变化,浏览器却不刷新页面
  • 用户以为这是多页面,其实都是同一个 HTML 文件
  • 全靠前端维护"假路由"+ 页面渲染

这,就是现代前端的开发


✅ 总结:一图秒懂,前端路由技术大比拼

技术 地址栏会变吗? 页面会刷新吗? 能否监听变化事件? SEO 友好吗?
hash 路由 ✅(监听 hashchange ❌,搜索引擎爬虫不友好
history.pushState ✅(监听 popstate ✅(配合服务端渲染SSR)

细节补充

  • hash 路由 :基于 URL 的 # 符号实现,兼容性极佳,但 URL 不够美观且对 SEO 支持有限。
  • history API :通过 pushStatereplaceState 修改浏览器地址栏,实现真正意义上的"无刷新路由切换",也方便后续和后端进行统一路由管理,SEO 友好。

最后聊聊"前端路由的秘密武器"------history.pushState

虽然这个 API 看起来简单,但它却是现代前端框架(React Router、Vue Router、Angular Router 等)坚实的基石。它让网页看起来像传统多页应用一样流畅切换,实际上却是单页面应用在背后"玩魔法":

  • 地址栏地址变了,用户感觉跳转了新页面
  • 但其实页面没有刷新,用户体验大幅提升
  • 浏览器返回前进按钮依然可用,历史管理有条理
  • SEO 通过服务端渲染(SSR)配合,可实现友好索引

你的收获

现在,你不仅能轻松写出"点按钮不刷新页面"的 SPA 路由,还知道:

  • 浏览器历史记录到底是什么鬼
  • pushStatereplaceState 有什么差别
  • 为什么要监听 popstate 事件
  • 传统 hash 路由为什么不够用
  • HTML5 history API 的巨大优势

这就是你成为前端路由高手的第一步!


如果你觉得这篇文章对你有帮助

请给我点个赞👍,收藏一下,转发给正在迷茫的同学们!

让更多人一起打破"刷新页面才跳转"的迷思,拥抱前端技术的美好未来!

相关推荐
吹牛不交税18 分钟前
Axure RP Extension for Chrome插件安装使用
前端·chrome·axure
薛定谔的算法34 分钟前
# 前端路由进化史:从白屏到丝滑体验的技术突围
前端·react.js·前端框架
拾光拾趣录2 小时前
Element Plus表格表头动态刷新难题:零闪动更新方案
前端·vue.js·element
Adolf_19932 小时前
React 中 props 的最常用用法精选+useContext
前端·javascript·react.js
前端小趴菜052 小时前
react - 根据路由生成菜单
前端·javascript·react.js
喝拿铁写前端2 小时前
`reduce` 究竟要不要用?到底什么时候才“值得”用?
前端·javascript·面试
空の鱼2 小时前
js与vue基础学习
javascript·vue.js·学习
鱼樱前端2 小时前
2025前端SSR框架之十分钟快速上手Nuxt3搭建项目
前端·vue.js
極光未晚2 小时前
React Hooks 中的时空穿梭:模拟 ComponentDidMount 的奇妙冒险
前端·react.js·源码
Codebee3 小时前
OneCode 3.0 自治UI 弹出菜单组件功能介绍
前端·人工智能·开源