一、前言
本文从传统页面开发的局限,到前端路由的实现原理来详细讲解SPA架构模式。
二、传统页面开发的局限
在传统的多页面开发模式下,每次用户点击导航链接,浏览器都会向服务器请求新的 HTML 页面,整个页面会被重新加载和渲染。这种方式有以下缺点:
- 全页刷新:每次跳转都会刷新整个页面,用户体验不佳。
- 白屏现象:页面切换时会出现短暂的空白,影响流畅性。
- 资源浪费:重复加载相同的资源(如 CSS、JS),增加带宽消耗。
<!-- 1.html/2.html 传统页面导航 -->
<nav>
<ul>
<li><a href="./1.html">Page 1</a></li>
<li><a href="./2.html">Page 2</a></li>
</ul>
</nav>
每次点击链接,都会重新加载页面。
三、前端路由的实现原理
1. Hash 路由
Hash 路由是最早被广泛应用于前端路由的方案。它利用 URL 的 #(哈希)部分来标识不同的页面状态。例如:http://example.com/#/about。当 # 后面的内容发生变化时,浏览器不会向服务器发起请求,也不会刷新页面,而是触发 hashchange 事件。前端可以监听这个事件,根据 hash 的值动态渲染不同的内容。
优点:
- 实现简单,无需服务器配合。
- 兼容性好,几乎所有浏览器都支持。
缺点:
- URL 中会带有
#,不够美观。 - 不利于 SEO(搜索引擎优化)。
示例代码:
window.addEventListener("hashchange", function () {
// 根据 location.hash 渲染页面
});
2. History 路由
HTML5 引入了 History API(如 pushState、replaceState),允许开发者在不刷新页面的情况下修改浏览器的 URL。例如:history.pushState({}, '', '/about')。这种方式可以让 URL 看起来更自然(如 /about),更接近传统多页面应用。
优点:
- URL 更加美观、规范。
- 更有利于 SEO(配合服务端渲染或预渲染)。
缺点:
- 需要服务器支持:所有路由都要返回同一个 HTML 文件,否则刷新页面会 404。
- 兼容性略低于 hash(但现代浏览器都已支持)。
示例代码:
history.pushState({}, "", "/about");
window.addEventListener("popstate", function () {
// 根据 location.pathname 渲染页面
});
四、SPA架构模式
SPA(Single Page Application,单页应用)是一种网页应用或网站的架构模式。它的核心特点是整个应用只有一个 HTML 页面,所有的页面内容和交互都通过 JavaScript 动态加载和切换,无需每次跳转都向服务器请求新的 HTML 页面。
详解之什么叫单页面?
可见往期文章玩转智能前端:SSE配合流式输出的奥秘中有关于SSE(Server-Sent Events,服务端推送事件) 的内容,
用户访问网站时,服务器会只返回一个HTML文件,后续的页面切换与内容更新都在这个页面内通过JS完成。
SPA 的优点是什么?
页面切换快,不会出现页面切换时的短暂白屏,用户体验好。实现前后端分离,提高开发效率,更易于维护,此外,也可以实现更复杂的交互和动画效果。
SPA 的缺点是什么?
首次加载时需要下载较多的 JS 资源,首屏加载速度可能较慢,并且SEO(搜索引擎优化)难度较大,需要配合服务端渲染(SSR)或预渲染。浏览器前进/后退、刷新等行为需要特殊处理。
开发SPA主流的选择
实现SPA最常用、最流行的前端开发框架和它们路由的解决方案有以下三种:
1. React(配合 React Router)
React 是一个由 Facebook 推出的用于构建用户界面的 JavaScript 库,非常适合开发 SPA。
React Router 是 React 生态中专门用于实现前端路由的库,可以让你在单页应用中实现多页面的导航和切换。
2. Vue(配合 Vue Router)
Vue 是一个轻量级、易上手的前端框架,也非常适合开发 SPA。
Vue Router 是 Vue 官方提供的路由库,用于在 Vue SPA 项目中实现页面切换和路由管理。
3. Angular
Angular 是 Google 推出的前端框架,功能非常强大,内置了自己的路由系统,适合开发大型的 SPA 项目。
以 React Router 为例,核心思想是通过 <BrowserRouter> 或 <HashRouter> 包裹应用,使用 <Routes> 和 <Route> 声明路由规则,利用 useNavigate、useLocation 等钩子实现编程式导航和路由信息获取。
代码如下:
import React from "react";
import { BrowserRouter, Routes, Route, Link, useNavigate, useLocation } from "react-router-dom";
// 首页组件
function Home() {
const navigate = useNavigate();
return (
<div>
<h2>首页</h2>
<button onClick={() => navigate("/about")}>跳转到关于页</button>
</div>
);
}
// 关于页组件
function About() {
const location = useLocation();
return (
<div>
<h2>关于页</h2>
<p>当前路径:{location.pathname}</p>
</div>
);
}
// 404组件
function NotFound() {
return <h2>页面未找到</h2>;
}
// 主应用
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">首页</Link> | <Link to="/about">关于</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
export default App;
参考资料: