Vue进阶系列第3篇:什么是SPA(单页面应用)? 如何实现一个简单的SPA?
Last updated on December 28, 2025 pm
大家好,我是jvxiao。
这是Vue从入门到精通系列文章的第3篇,今天我们来谈谈和Vue紧密相关的一个东西–SPA。此SPA非各位日常生活中的养生SPA, 而是单页面应用(Single Page Application)。
在现代前端开发中,单页面应用(SPA)已成为主流架构之一,Vue、React、Angular 等框架均以 SPA 为核心设计理念。它凭借流畅的交互体验、高效的资源利用,广泛应用于后台管理系统、移动端应用等场景。
本文将从基础概念出发,对比 SPA 与传统多页面应用(MPA)的核心差异,并通过极简代码实现 hash 模式 SPA,帮助大家快速掌握其工作原理。
一、什么是 SPA(单页面应用)
SPA(Single Page Application)即单页面应用,是一种仅加载一个核心 HTML 文件的 Web 应用架构。其核心特征是:页面内容的更新不依赖浏览器的整页刷新,而是通过 JavaScript 动态操作 DOM 节点、异步请求数据,实现视图的局部更新。
可以通俗地理解为:SPA 就像一个 “固定外壳” 的房子,首次加载时会完整加载房屋的基础结构(核心 HTML、CSS、JS),后续切换 “房间”(页面视图)时,无需更换房子本身,只需通过 JS 动态替换内部的 “家具”(DOM 内容)。这种设计让应用交互更接近原生 App,避免了传统页面跳转时的加载等待感。
SPA 的核心技术支撑包括:
- 前端路由:管理 URL 与视图的映射关系,实现无刷新跳转;
- 动态 DOM 操作:通过 JS 修改页面内容,而非重新加载 HTML;
- 异步数据请求:通过 AJAX/ Fetch 获取后端数据,更新视图内容。
二、SPA 与 MPA(多页面应用)的核心差异
传统多页面应用(MPA,Multi Page Application)与 SPA 在架构设计、交互逻辑上存在本质区别,以下从 6 个核心维度对比分析:
1. 页面结构SPA:仅包含 1 个核心 HTML 文件,所有视图均基于该文件通过 JS 动态生成;MPA:包含多个独立的 HTML 文件,每个页面对应一个单独的 HTML 资源(如首页 index.html、关于页 about.html)。
2. 跳转机制SPA:通过前端路由实现跳转(如 hash/history 模式),URL 变化时不会触发浏览器整页刷新,仅更新局部 DOM;MPA:通过浏览器原生跳转(a 标签、表单提交、location.href)实现页面切换,每次跳转都会重新加载整个 HTML、CSS、JS 资源,浏览器会显示加载状态。
资源加载
SPA:首次加载时会加载所有核心资源(框架、公共 JS/CSS、路由配置),后续仅需按需加载接口数据,资源复用率高;MPA:每次页面跳转都需重新加载对应页面的全部资源(HTML 结构、页面专属 CSS/JS),资源重复加载较多。交互体验
SPA:首次加载可能因资源较多稍慢,但后续交互无刷新延迟,流畅度接近原生应用;MPA:每次跳转都存在资源加载等待,交互体验相对卡顿,尤其在网络环境较差时表现明显。SEO 友好性
SPA:天生存在 SEO 劣势 —— 页面内容由 JS 动态生成,传统搜索引擎爬虫难以抓取动态渲染的内容,需通过 SSR(服务端渲染)等方案优化;MPA:页面内容静态嵌入 HTML,搜索引擎爬虫可直接抓取,SEO 天然友好,适合资讯、官网等需要曝光的场景。适用场景
SPA:更适合交互频繁、对体验要求高的应用,如后台管理系统、移动端 App、社交应用等;MPA:更适合内容分散、无需复杂交互的场景,如资讯网站、企业官网、电商商品列表页等。
三、hash 模式 SPA 的实现原理与极简案例
在 SPA 的前端路由方案中,hash 模式是最简易、兼容性最强的实现方式。其核心依赖 URL 中 “#” 符号的特性:
hash 模式核心原理
- URL 中 “#” 后面的部分(hash 值)属于客户端标识,其变化不会触发浏览器整页刷新,也不会向服务器发送请求;
- 当 hash 值发生变化时,浏览器会触发
hashchange事件,前端可监听该事件,根据不同的 hash 值动态更新视图。
基于这两个特性,可实现 “URL 变化→事件触发→视图更新” 的闭环,完成无刷新跳转。
极简 hash 模式 SPA 实现代码
以下是完整可运行的原生 JS 代码,保存为 spa-demo.html 直接在浏览器打开即可体验:
1 | |
3. 代码核心逻辑解析
(1)路由规则定义(routeConfig)
路由表是 SPA 的 “导航地图”,定义了不同 hash 路径与页面内容的映射关系。实际项目中,“content” 会替换为 Vue/React 组件,此处用原生 HTML 字符串简化演示。
(2)渲染函数(renderView)
SPA 核心逻辑,负责根据当前 hash 更新页面内容:
- 获取 hash 值:通过
window.location.hash获取 URL 中 “#” 后内容,默认值为#/home; - 匹配路由:用
find方法查找当前 hash 对应的路由,未匹配则返回 404; - 动态更新 DOM:将匹配到的内容插入视图容器
view-container,实现局部更新; - 导航高亮:通过操作 DOM 类名,高亮当前选中导航项,提升交互体验。
(3)事件监听
hashchange事件:用户点击导航或手动修改 hash 时触发,调用renderView重新渲染;load事件:页面首次加载时触发,初始化显示首页内容。
SPA 的优势与局限
1. 核心优势
- 交互体验流畅:无整页刷新,切换视图无延迟,接近原生 App;
- 资源利用率高:首次加载核心资源后,后续仅加载数据,减少网络请求;
- 前后端分离:前端独立控制渲染,后端仅提供接口,职责清晰;
- 适配性强:易于适配移动端、桌面端等多终端。
2. 主要局限
- 首次加载速度慢:需一次性加载核心 JS/CSS,资源体积大时会有延迟;
- SEO 优化困难:传统爬虫难抓取动态内容,需 SSR/预渲染等方案优化;
- 兼容问题:早期浏览器对
hashchange支持有限(现代浏览器已兼容),history 模式需后端配置。
五、写在最后
如果你认真阅读了上述内容并自己跑了一遍代码,想必你也基本掌握了SPA的工作原理了。
在本文中实现的 hash 模式 SPA 存在 URL 含 # 的问题,实际项目中更常用 history 模式,核心依赖 HTML5 的 history.pushState() 和 history.replaceState() 方法,可实现无 # 的简洁 URL。
大家可以尝试对上述代码进行改造实现,也可以此基础上扩展:引入组件化、添加异步请求、实现路由守卫等,逐步接近真实项目架构。
上周有点懒,更新的频率有点低,这周争取3篇文章,最少两篇,感谢大家的支持哈!
【往期精彩】