目录
- 一、「前端路由」概念
- 二、前端路由的核心本质
- 三、前端路由的两种实现方式------hash路由和history路由
-
- 1、两种路由的本质区别
- 2、两种路由原理的核心对比(⭐️⭐️⭐️⭐️⭐️)
-
- [(1)、Hash 路由原理](#(1)、Hash 路由原理)
- [(2)、History 路由原理](#(2)、History 路由原理)
- [(3)、为什么 History 路由需要后端配合?](#(3)、为什么 History 路由需要后端配合?)
- 3、两种路由的使用建议(场景)
- [四、Vue Router / React Router 底层是怎么封装这两种模式(Hash & History)的?(⭐️⭐️⭐️)](#四、Vue Router / React Router 底层是怎么封装这两种模式(Hash & History)的?(⭐️⭐️⭐️))
-
- 1、路由库的完整工作链路
- 2、四层封装
-
- [(1)、第 1 层:对浏览器路由能力的封装](#(1)、第 1 层:对浏览器路由能力的封装)
- [(2)、第 2 层:路径匹配系统](#(2)、第 2 层:路径匹配系统)
- [(3)、第 3 层:和框架渲染系统打通](#(3)、第 3 层:和框架渲染系统打通)
-
- [①、Vue Router 做的事](#①、Vue Router 做的事)
- [②、React Router 做的事](#②、React Router 做的事)
- [(4)、第 4 层:拦截浏览器默认跳转](#(4)、第 4 层:拦截浏览器默认跳转)
-
- [①、React Router 的 `<Link>`](#①、React Router 的
<Link>) - [②、Vue Router 的 `<router-link>`](#②、Vue Router 的
<router-link>)
- [①、React Router 的 `<Link>`](#①、React Router 的
- [3、Hash vs History 在框架中的区别](#3、Hash vs History 在框架中的区别)
一、「前端路由」概念
前端路由是单页应用中的页面管理机制,通过监听 URL 的变化并在客户端动态渲染不同组件,实现无刷新页面切换。其核心是路径与组件的映射,常见实现方式有 Hash 模式和 History 模式,前者基于 hashchange,后者基于 HTML5 History API。
前端路由就是:在不刷新整个页面的情况下,根据 URL 的变化切换页面内容。也就是 ------ 看起来在跳页面,其实只是在换组件。
二、前端路由的核心本质
其实就干了两件事:
| 功能 | 本质行为 |
|---|---|
| 改变 URL | 不刷新页面 |
| 根据 URL 显示不同内容 | 动态渲染不同组件 |
所以前端路由 =
typescript
监听 URL 变化 → 找到匹配规则 → 渲染对应组件
三、前端路由的两种实现方式------hash路由和history路由
- Hash 路由(最早期方案)
- History 路由(现代主流)
1、两种路由的本质区别
| 核心差异 | 解释 |
|---|---|
| Hash 是锚点变化 | 只在浏览器本地生效 |
| History 是路径变化 | 浏览器认为是"真实地址" |
2、两种路由原理的核心对比(⭐️⭐️⭐️⭐️⭐️)
| 对比项 | Hash 路由 | History 路由 |
|---|---|---|
| URL 形式 | example.com/#/home |
example.com/home |
| 路由标识符 | # 后面的内容 |
完整路径 |
| 是否会请求服务器 | ❌ 不会 | ✅ 会(刷新时) |
| 实现原理 | 监听 hashchange |
使用 history.pushState |
| 是否需要后端配合 | ❌ 不需要 | ✅ 需要 |
| 刷新页面是否 404 | 不会 | 可能会 |
| SEO 友好度 | 差 | 好 |
| 兼容性 | 非常好(IE8+) | 需要 HTML5 支持 |
| 浏览器前进后退 | 支持 | 支持 |
| 安全性(锚点特性) | 类似页面锚点 | 真正的路径 |
(1)、Hash 路由原理
URL 示例:
typescript
https://example.com/#/user
特点:
#后面的内容叫 hash- hash 改变 不会触发浏览器向服务器发请求
- 浏览器只会在本地触发:
typescript
window.onhashchange
所以页面看起来切换了,其实始终是同一个 HTML 文件。
(2)、History 路由原理
URL 示例:
typescript
https://example.com/user
核心 API:
typescript
history.pushState()
history.replaceState()
window.onpopstate
它是通过 修改浏览器历史记录 来改变 URL,但不会刷新页面
但有个关键问题:
- 当用户刷新页面时,浏览器真的会请求 /user 这个路径
- 如果服务器没有配置,就会------返回 404
(3)、为什么 History 路由需要后端配合?
因为刷新时:
- 浏览器:GET /user
- 服务器:???
正确做法是让服务器:
- 无论访问什么路径,都返回同一个 index.html
- 由前端路由接管页面渲染
例如 Nginx 配置:
typescript
location / {
try_files $uri /index.html;
}
3、两种路由的使用建议(场景)
| 场景 | 推荐路由模式 |
|---|---|
| 后端无法改配置 | Hash |
| 需要 SEO | History |
| 移动端 SPA | History(主流) |
| 内网系统 | Hash 或 History 都行 |
四、Vue Router / React Router 底层是怎么封装这两种模式(Hash & History)的?(⭐️⭐️⭐️)
Vue Router 和 React Router 本质都干了同一件事:
- 把"浏览器地址变化"封装成"组件切换机制"
Vue Router 和 React Router 底层都是对浏览器 History API 和 hash 机制的封装。它们通过监听 URL 变化(hashchange 或 popstate),维护一套路由匹配规则,并将匹配结果映射为组件渲染,同时拦截链接点击以避免页面刷新,从而实现单页应用(spa)的前端路由系统。
1、路由库的完整工作链路
typescript
用户点击链接
↓
阻止浏览器默认刷新
↓
调用 pushState / 改变 hash
↓
浏览器地址改变
↓
路由库监听到变化
↓
路径匹配算法找到对应组件
↓
触发框架重新渲染
↓
页面内容更新(无刷新)
2、四层封装
(1)、第 1 层:对浏览器路由能力的封装
浏览器只提供了这两种能力:
| 模式 | 浏览器 API |
|---|---|
| Hash | hashchange |
| History | pushState + popstate |
路由库会先封装一个"历史管理器"(history manager):
- Hash 模式监听:
typescript
window.addEventListener("hashchange", () => {
notify(location.hash.slice(1))
})
- History 模式监听:
typescript
window.addEventListener("popstate", () => {
notify(location.pathname)
})
然后统一对外暴露:
typescript
history.push("/about")
history.replace("/login")
history.listen(callback)
- React Router 里就有
createHashHistory和createBrowserHistory。 - Vue Router 也是同样的两种实现,只是名字叫:
createWebHashHistory和createWebHistory
(2)、第 2 层:路径匹配系统
路由库会维护一张 路由表:
typescript
[
{ path: "/", component: Home },
{ path: "/about", component: About },
{ path: "/user/:id", component: User }
]
当 URL 变化时:
typescript
const matchedRoute = matchRoutes(routes, currentPath)
这里会做:
- 动态参数解析
/user/123 - 嵌套路由匹配
- 通配符匹配
*
(3)、第 3 层:和框架渲染系统打通
①、Vue Router 做的事
当路径变化:
typescript
currentRoute.value = newRoute
<router-view> 是个响应式组件:
typescript
watch(currentRoute, () => {
render(matchedComponent)
})
所以 URL 一变,组件自动重新渲染。
②、React Router 做的事
React Router 内部用 Context 存当前 location:
typescript
const LocationContext = React.createContext()
当路径变化时更新 context:
typescript
setState({ location: newLocation })
<Routes> 组件重新 render,根据 path 匹配渲染对应组件。
(4)、第 4 层:拦截浏览器默认跳转
为什么点击
<a>不刷新页面?
因为路由库接管了点击事件。
①、React Router 的 <Link>
typescript
function Link({ to }) {
return <a onClick={(e) => {
e.preventDefault()
history.push(to)
}} />
}
②、Vue Router 的 <router-link>
同理,阻止默认跳转,改用 pushState。
3、Hash vs History 在框架中的区别
| 项目 | HashRouter | BrowserRouter (History) |
|---|---|---|
| URL 形式 | /#/about |
/about |
| 底层监听 | hashchange |
popstate |
| push 方法 | 改 location.hash |
history.pushState |
| 需后端配合 | ❌ | ✅ |
| SEO | 差 | 好 |