1. SPA与路由基础:从传统页面到现代应用

大家好,我是这门课的主讲。今天咱们聊聊SPA和路由——这两个词你可能听过无数遍了,但真正理解它们背后的设计哲学,还是得从最基础的地方说起。

1.1 什么是SPA?

SPA,全称Single Page Application,单页应用。说白了,就是整个网站只有一个HTML页面。你点来点去,页面不会整个刷新,只有局部内容在变。

我刚开始做前端那会儿,听到这个概念还觉得挺玄乎。后来自己动手写了一个,才明白——SPA的核心,就是让前端接管路由控制权

SPA的本质特征:

  • 首次加载一个完整的HTML页面
  • 后续操作通过AJAX获取数据
  • 前端JavaScript动态渲染视图
  • 页面不会整页刷新

1.2 传统多页应用 vs SPA

咱们先看看传统多页应用长什么样。你访问一个网站,点个链接,浏览器地址栏变了,然后整个页面白一下,重新加载。每次跳转,服务器都要返回一个新的HTML。

对比维度 传统多页应用 SPA单页应用
页面切换 整页刷新 局部更新
用户体验 有白屏闪烁 流畅顺滑
前后端耦合 强耦合 解耦
首屏加载 快(只加载当前页) 慢(需加载完整框架)
SEO友好度 差(需SSR辅助)
开发复杂度

嗯,这里要注意。SPA虽然体验好,但首屏加载确实是个痛点。我在一个移动端项目里就踩过这个坑——用户打开页面要等3秒才能看到内容,流失率直接翻倍。后来用了代码分割和懒加载,才把首屏时间压到1秒以内。

1.3 前端路由原理

路由,说白了就是URL和视图的对应关系。传统多页应用里,路由是服务器管的。你访问/about,服务器就返回about.html。但在SPA里,所有页面都在一个HTML里,谁来管这个对应关系?

答案就是——前端路由

前端路由的核心思路是:监听URL的变化,然后根据URL匹配对应的组件,渲染到页面上。整个过程不需要请求服务器。

我个人习惯:把前端路由理解成一个“映射表”。URL是key,组件是value。URL变了,就查表找到对应的组件,渲染出来。

1.4 Hash模式

Hash模式是最早的前端路由实现方式。它利用URL中#号后面的部分来模拟路由。

比如:https://example.com/#/home,这里的#/home就是hash值。

为什么hash能实现前端路由?因为hash的变化不会触发页面刷新,但会触发hashchange事件。我们可以监听这个事件,然后做视图切换。

// 一个简单的Hash路由实现
window.addEventListener('hashchange', function() {
  const hash = window.location.hash.slice(1); // 去掉#号
  switch(hash) {
    case '/home':
      renderHome();
      break;
    case '/about':
      renderAbout();
      break;
    default:
      renderNotFound();
  }
});

// 手动修改hash
window.location.hash = '/about';

我曾经在一个老项目里用过Hash模式。当时客户要求兼容IE8,History模式根本不能用,Hash模式是唯一选择。不过说实话,Hash模式的URL带个#号,看着确实不太优雅。

注意:Hash模式虽然兼容性好,但SEO极差。搜索引擎爬虫通常不会执行JavaScript,所以爬虫看到的永远是一个空壳页面。如果你的网站需要SEO,Hash模式基本不可用。

1.5 History模式

History模式是HTML5提供的API,它让前端路由可以操作浏览器的历史记录,同时不刷新页面。

核心API就两个:

  • history.pushState() — 添加一条历史记录
  • history.replaceState() — 替换当前历史记录

再加上popstate事件,就能实现完整的前端路由了。

// History模式路由示例
function navigate(path) {
  // 改变URL,不刷新页面
  history.pushState({ path }, '', path);
  // 手动渲染对应视图
  renderView(path);
}

// 监听浏览器前进/后退
window.addEventListener('popstate', function(event) {
  const path = window.location.pathname;
  renderView(path);
});

// 使用
navigate('/about'); // URL变成 /about,页面不刷新

History模式的URL看起来和传统多页应用一模一样,没有#号。用户体验更好,SEO也相对友好一些。

但有个大坑——服务器配置。你想想看,用户直接访问/about,服务器找不到这个路径,就会返回404。所以你必须配置服务器,把所有路径都指向index.html,让前端路由来处理。

两种模式对比:

特性 Hash模式 History模式
URL样式 带#号 正常URL
兼容性 IE8+ IE10+
服务器配置 无需特殊配置 需配置fallback
SEO 相对较好
实现复杂度

1.6 我的建议

做新项目,我建议优先选History模式。虽然服务器配置麻烦一点,但URL干净,用户体验好。而且现在主流框架(Vue Router、React Router)默认都用History模式。

但如果你要兼容老旧浏览器,或者项目部署在静态文件服务器上(比如GitHub Pages),那Hash模式更省心。

嗯,这一章就到这里。下一章咱们会手写一个迷你路由,把今天讲的原理落地成代码。到时候你就知道,路由这东西,说白了就是个监听器加映射表,没那么神秘。

避坑指南:我曾经在一个项目里混用了Hash和History两种模式,结果导致路由跳转逻辑混乱,调试了一整天。记住,一个项目只用一种模式,别搞混了。