1. SPA(单页面应用)
如何理解SPA
SPA是Single-Page-Application的缩写,翻译过来就是单页应用。在WEB页面初始化时一同加载Html、Javascript、Css。一旦页面加载完成,SPA不会因为用户操作而进行页面重新加载或跳转,取而代之的是利用路由机制实现Html内容的变换。
1.1.1. 优点
- 良好的用户体验,内容更改无需重载页面。
- 基于上面一点,SPA相对服务端压力更小。
- 前后端职责分离,架构清晰。
1.1.2. 缺点
- 由于单页WEB应用,需在加载渲染页面时请求JavaScript、Css文件,所以耗时更多。
- 由于前端渲染,搜索引擎不会解析JS,只能抓取首页未渲染的模板,不利于SEO。
- 由于单页应用需在一个页面显示所有的内容,默认不支持浏览器的前进后退。
关于缺点3
其实是前端路由机制解决了单页应用无法前进后退的问题。Hash模式中Hash变化会被浏览器记录(onhashchange事件),History模式利用 H5 新增的pushState和replaceState方法可改变浏览器历史记录栈。
2. SPA和多页面(MPA)的区别
2.1. 工作原理区别
| 特性 | MPA (多页应用) | SPA (单页应用) |
|---|---|---|
| 页面结构 | 每个页面对应一个独立的 .html 文件。 | 整个项目通常只有一个 .html 文件(入口文件)。 |
| 跳转机制 | 整页刷新。点击链接时,浏览器向服务器请求新的 HTML,然后重新渲染整个页面。 | 局部刷新。点击链接时,前端拦截请求,通过 JavaScript (AJAX/Fetch) 获取数据,动态替换页面中的某一部分内容 (DOM)。 |
| 路由处理 | 服务端路由。URL 的变化由服务器解析并返回对应的 HTML。 | 前端路由。URL 的变化由前端 JS 库 (如 Vue Router, React Router) 监听和处理,服务器通常只配置一个通配符指向入口文件。 |
| 资源加载 | 每次跳转都会重新加载 CSS/JS (除非做了强缓存),但首屏只需加载当前页资源。 | 首次加载需下载所有必要的 JS/CSS (包体积大),后续跳转通常不再加载新资源,或仅加载按需拆分的代码块。 |
2.2. 优缺点
2.2.1. MPA (多页应用)
- ✅ 优点:
-
- SEO (搜索引擎优化) 友好:服务器直接返回完整的 HTML,搜索引擎爬虫能轻松抓取内容,无需执行 JS。
- 首屏速度快:用户访问第一个页面时,只需下载该页面的资源,无需等待庞大的 JS 框架加载。
- 开发简单:传统模式,前后端耦合度高(如 JSP, PHP, Django Templates),逻辑直观。
- ❌ 缺点:
-
- 体验较差:页面切换时有明显的“白屏”或闪烁感,流畅度不如原生 App。
- 重复传输:每个页面的 Header、Footer 等公共部分在每次请求中都会重复传输 HTML 代码。
- 状态保持难:页面刷新后,前端的状态(如滚动位置、表单输入)会丢失。
2.2.2. SPA (单页应用)
- ✅ 优点:
-
- 用户体验极佳:页面无刷新切换,操作流畅,接近原生 App 的体验。
- 前后端分离:前端专注 UI 和交互,后端专注 API 数据,职责清晰,便于并行开发和多端复用(App/小程序/Web 共用一套 API)。
- 减少服务器压力:服务器只需返回 JSON 数据,不需要渲染 HTML,计算压力转移到了客户端。
- ❌ 缺点:
-
- SEO 困难:初始 HTML 通常为空,内容靠 JS 动态生成。虽然现代搜索引擎(Google, 百度)已能执行 JS,但仍不如 MPA 直接,通常需要配合 SSR (服务端渲染) 或 预渲染 技术解决。
- 首屏加载慢:首次访问需要下载较大的 JS bundle,用户可能需要等待几秒才能看到内容(可通过代码分割、懒加载优化)。
- 内存泄漏风险:长期不刷新页面,如果 JS 代码管理不当,容易导致浏览器内存占用越来越高。
2.3. 应用场景
| 场景类型 | 推荐架构 | 理由 | 典型例子 |
|---|---|---|---|
| 内容展示型 | MPA (或 SSR) | 重视 SEO,首屏速度至关重要,交互相对简单。 | 新闻门户、博客、企业官网、电商详情页 |
| 复杂交互型 | SPA | 重视用户体验,操作频繁,类似桌面软件或 App。 | 在线文档 (Google Docs)、后台管理系统、SaaS 平台、即时通讯 |
| 混合型 | SSR / 同构 | 既要 SEO 又要好体验。现代框架 (Next.js, Nuxt.js) 的主流做法。 | 大型电商平台 (淘宝/京东的部分页面)、社交媒体 |
3. 实现路由的两种模式
- 前端路由有两种模式:hash 模式和 history 模式,接下来分析这两种模式的实现方式和优缺点。
- hash模式 开发中默认的模式,地址栏URL后携带#,后面为路由。 原理是通过onhashchange()事件监听hash值变化,在页面hash值发生变化后,window就可以监听到事件改变,并按照规则加载相应的代码。hash值变化对应的URL都会被记录下来,这样就能实现浏览器历史页面前进后退。
- history模式 history模式中URL没有#,这样相对hash模式更好看,但是需要后台配置支持。
-
- history原理是使用HTML5 history提供的pushState、replaceState两个API,用于浏览器记录历史浏览栈,并且在修改URL时不会触发页面刷新和后台数据请求。
| 特性 | Hash 模式 (#/) | History 模式 (/) |
|---|---|---|
| URL 外观 | 丑,带 # (例: /#/about) | 美,标准路径 (例: /about) |
| 原理 | 监听 hashchange 事件 | 使用 HTML5 history.pushState |
| HTTP 请求 | # 后内容不发给服务器 | 完整路径会发给服务器 |
| 刷新页面 | 正常,不会 404 | 若未配置服务器,会 404 |
| 服务器配置 | 无需配置 | 必须配置 (所有路径指向 index.html) |
| SEO | 一般 | 较好 |
| 兼容性 | 极好 (支持 IE8) | 好 (IE10+) |
3.1. hash模式
3.1.1. URL 长什么样?
URL 中包含一个 # 符号,# 后面的内容就是 Hash 值。
示例:https://www.example.com/#/home 或 https://www.example.com/#/user/123
3.1.2. 工作原理
- 浏览器行为:
#及其后面的内容被称为“哈希片段”。浏览器在发送 HTTP 请求给服务器时,永远不会包含 ****#****后面的内容。
-
- 当你访问
example.com/#/about时,浏览器实际只向服务器请求了example.com/。- 服务器配置:不需要任何特殊配置。因为服务器收到的永远只是根路径/,它只需要返回那个唯一的index.html即可,剩下的交给前端处理。
- 当你访问
3.1.3. 优缺点
- ✅ 优点:
-
- 兼容性好:支持所有浏览器,包括古老的 IE8。
- 部署简单:后端无需任何配置,直接丢到静态服务器(如 Nginx, GitHub Pages)就能跑。
- 状态安全:刷新页面不会导致 404,因为服务器根本没看到 Hash 部分。
- ❌ 缺点:
-
- URL 不美观:带着一个
#号,看起来像是一个临时锚点,不够专业。 - SEO 稍差:虽然现在的搜索引擎能抓取 Hash 内容,但权重通常不如普通 URL。
- 传递参数受限:虽然可以传参,但不如标准 URL 查询参数直观。
- URL 不美观:带着一个
3.2. history模式
3.2.1. URL 长什么样?
URL 看起来像传统的多页应用路径,干净清爽,没有 #。
示例:https://www.example.com/home 或 https://www.example.com/user/123
3.2.2. 工作原理
- 核心技术:利用 HTML5 提供的
history.pushState()和history.replaceState()API。
-
- 这两个方法可以改变浏览器的 URL 栏内容,并压入历史记录栈,但不会向服务器发送请求。
- 前端监听:前端监听
popstate事件(用户点击浏览器后退/前进按钮时触发),匹配 URL 路径并渲染对应组件。 - 服务器配置(关键点!) :
-
- 问题:如果用户直接在浏览器地址栏输入
example.com/user/123并回车,或者刷新页面,浏览器会真的向服务器发送请求,请求/user/123这个资源。 - 后果:如果服务器上没有配置
/user/123这个文件,服务器会返回 404 Not Found。 - 解决方案:必须在后端服务器(Nginx, Apache, Node.js 等)配置一条通配符规则: “无论用户请求什么路径,只要找不到对应的静态文件,统统返回 ****
index.html” 。这样,前端拿到index.html后,JS 加载运行,读取当前 URL,再由前端路由接管渲染。
- 问题:如果用户直接在浏览器地址栏输入
3.2.3. 优缺点
- ✅ 优点:
-
- URL 美观:符合人类阅读习惯,看起来像正常的网站路径。
- SEO 友好:搜索引擎更喜欢这种标准的 URL 结构。
- 语义化强:路径清晰,易于分享和记忆。
- ❌ 缺点:
-
- 需要后端配合:必须配置服务器重定向规则,否则刷新会 404。
- 兼容性略低:不支持 IE9 及以下(不过现在基本不用考虑 IE 了)。