前言
上一篇文章我们是从hash
技术原理出发,探讨前端路由的实现过程。所以这篇文章我们要讲另一种技术原理也就是history
来实现前端路由,在前端路由实现中,History API 是一种较新的、更加优雅的方案,它能够修改浏览器的 URL 而不触发页面刷新,同时提供丰富的历史记录管理功能。相比于传统的 Hash 路由,History API 的 URL 更加清晰和符合 RESTful 设计规范,并且有助于改善用户体验。我们在本文将深入解析 History API 的核心方法及其在前端路由中的应用。
正文
History API 核心概念
History API 允许开发者对浏览器的历史记录栈进行操作,包括添加、修改和替换历史记录条目。核心方法和事件包括:
-
pushState
方法:-
用于向历史记录栈中添加新的记录。
-
调用
pushState
后,浏览器地址栏会更新为指定的 URL,但不会触发页面刷新。 -
语法:
javascript 复制代码 history.pushState(state, title, url);
state
:任意 JavaScript 对象,表示与新历史记录关联的状态信息。title
:通常传入空字符串,因为大多数浏览器目前不使用该参数。url
:新的 URL 地址。
-
-
replaceState
方法:-
替换当前历史记录条目,而不是添加新条目。
-
使用场景:如在 SPA 中跳转到相同页面但需更新 URL 参数。
-
语法:
javascript 复制代码 history.replaceState(state, title, url);
-
-
popstate
事件:- 当用户点击浏览器的前进或后退按钮时,会触发
popstate
事件。 - 注意:调用
pushState
或replaceState
不会触发该事件,只有浏览器导航操作会触发。
- 当用户点击浏览器的前进或后退按钮时,会触发
代码示例
接下来我们直接用代码来讲解:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li><a href="/home">首页</a></li>
<li><a href="/about">关于</a></li>
</ul>
<div id="routeView">
<!-- 放一个代码片段 -->
</div>
<script>
const routes = [
{
path: '/home',
component: '<h2>首页页面内容</h2>',
},
{
path: '/about',
component: '<h3>about page</h3>'
}
]
const routeView = document.getElementById('routeView')
window.addEventListener('DOMContentLoaded', onLoad)
window.addEventListener('popstate', onPopState)
function onLoad() {
const links = document.querySelectorAll('li a')
links.forEach(a => {
a.addEventListener('click', (e) => {
e.preventDefault() // 阻止了a标签的默认跳转行为
// 添加一种可以修改url又不造成页面刷新
history.pushState(null, '', a.getAttribute('href'))
// 映射对应的dom
onPopState()
})
})
}
// const links = document.querySelectorAll('li a')
// links.forEach(a => {
// a.addEventListener('click', (e) => {
// e.preventDefault() // 阻止了a标签的默认跳转行为
// // 添加一种可以修改url又不造成页面刷新
// history.pushState(null, '', a.getAttribute('href'))
// // 映射对应的dom
// onPopState()
// })
// })
function onPopState() {
console.log(location.pathname);
routes.forEach(item => {
if (item.path === location.pathname) {
routeView.innerHTML = item.component
}
})
}
</script>
</body>
</html>
代码讲解
代码解析
-
HTML 部分:
<ul> <li><a href="/home">首页</a></li> <li><a href="/about">关于</a></li> </ul> <div id="routeView"> <!-- 放一个代码片段 --> </div>
- 导航链接:
<a>
标签作为路由链接,点击时会修改浏览器 URL 中的路径部分(例如/home
或/about
)。 routeView
容器:该容器用于动态渲染与当前 URL 路径对应的页面内容。
- 导航链接:
-
JavaScript 部分:
-
routes
配置:定义了一个路由配置对象数组,映射了路径和对应的组件(这里用 HTML 字符串表示)。const routes = [ { path: '/home', component: '<h2>首页页面内容</h2>', }, { path: '/about', component: '<h3>about page</h3>' } ]
-
事件监听:
DOMContentLoaded
事件:当文档加载完成后,执行onLoad
函数,初始化链接的事件处理。popstate
事件:监听浏览器的前进和后退操作,当用户改变浏览器历史记录时触发,执行onPopState
来更新页面内容。
-
-
onLoad
函数:function onLoad() { const links = document.querySelectorAll('li a'); links.forEach(a => { a.addEventListener('click', (e) => { e.preventDefault(); // 阻止a标签的默认跳转行为 history.pushState(null, '', a.getAttribute('href')); // 修改URL,但不刷新页面 onPopState(); // 更新页面内容 }); }); }
- 阻止默认跳转:通过
e.preventDefault()
阻止<a>
标签默认的跳转行为,避免触发页面刷新。 - 修改 URL:使用
history.pushState()
修改 URL 中的路径部分。此操作不会导致页面刷新,只是更新了浏览器的历史记录栈。 - 渲染视图:调用
onPopState()
,通过 URL 的变化来渲染相应的页面内容。
- 阻止默认跳转:通过
-
onPopState
函数:function onPopState() { console.log(location.pathname); routes.forEach(item => { if (item.path === location.pathname) { routeView.innerHTML = item.component; } }); }
location.pathname
:通过location.pathname
获取当前的 URL 路径。- 路由匹配:遍历
routes
数组,检查当前路径是否与路由配置中的path
匹配。 - 渲染对应组件:如果路径匹配,则将对应的
component
内容插入到routeView
容器中,从而更新页面内容。
小结
-
URL 路径与页面内容的映射: 通过将 URL 路径和页面内容进行映射(
routes
数组),实现了基于路径的页面切换。 -
使用
history.pushState
修改 URL:pushState
修改了浏览器的地址栏,而不引起页面的刷新。这是实现前端路由的核心机制,通过pushState
可以动态更新 URL。 -
popstate
事件监听: 当用户通过浏览器的前进和后退按钮导航时,popstate
事件会被触发,调用onPopState
更新页面内容。 -
避免页面刷新: 与传统的多页面应用不同,单页面应用通过修改 URL 来模拟页面切换,但不会重新加载页面。这样做大大提高了应用性能,减少了不必要的页面刷新。
总结
History 路由与 Hash 路由简要对比总结
-
Hash 路由:
- 原理:通过修改 URL 中的
#
符号后面的部分来实现路径切换,不会引起页面刷新。 - 优点:实现简单,不需要服务器配置,兼容性强。
- 缺点:URL 中包含
#
,不符合 RESTful 设计,SEO 不友好,功能上较为简单。
- 原理:通过修改 URL 中的
-
History 路由:
- 原理:通过 HTML5
History API
的pushState
和popState
方法修改浏览器历史记录和 URL,避免页面刷新。 - 优点:URL 清晰美观,符合 RESTful 设计,支持复杂路由和动态参数,SEO 友好。
- 缺点:需要服务器配置,支持较差的老旧浏览器,较 Hash 路由实现稍复杂。
- 原理:通过 HTML5
总的来说:
- Hash 路由:适合简单应用,兼容性好,使用方便,但 URL 不美观且 SEO 性能差。
- History 路由:适合需要清晰 URL 和 SEO 优化的应用,支持复杂功能,但需要服务器配置和兼容性管理。
无论你是前端新手还是资深开发者,掌握好 History 路由 和 Hash 路由 的区别,将让你在开发 SPA 时如虎添翼!当然,选择哪个方案也要看你的项目需求和兼容性要求。希望这篇文章能帮助你在路由的世界里迷失不再——别忘了给我点个赞,关注一下,带着你的小伙伴一起来探讨更多前端小技巧!🚀
祝你在代码的海洋中畅游,不迷路!👨💻👩💻