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两种模式,结果导致路由跳转逻辑混乱,调试了一整天。记住,一个项目只用一种模式,别搞混了。