前言
单页应用(Single Page Application,简称SPA)的设计模式在现代Web开发中变得越来越流行,主要因为它能提供类似桌面应用的用户体验。SPA通过动态加载和替换部分网页内容,而无需重新加载整个页面,这带来了快速响应和流畅的交互效果。然而,这种模式对传统的HTTP协议提出了挑战,因为HTTP本质上是无状态的,且服务器无法主动向客户端推送内容。因此,SPA需要一些技术来管理状态并实现页面的动态更新。
正文
使用Hash Router进行管理
在单页应用中,一个常见的解决方案是使用“Hash Router”。Hash Router利用URL中的hash(#)部分来区分不同的页面或视图。当用户在浏览器地址栏中修改URL的hash部分时,浏览器会触发hashchange
事件。开发者可以监听这个事件,并通过异步请求(如AJAX)从服务器获取数据,然后更新DOM以显示相应的视图。
有许多小白可能不懂什么意思
简单来说,在传统的多面应用中,每个页面都有独特的URL,例如我们从掘金首页
此时的URL为https://juejin.cn/
,而如果我们进入某一篇文章时,整个页面会重新加载并刷新
URL也会随之改变,使得页面会重新加载
URL的改变意味着浏览器需要重新向对应服务器发送请求,十分耗费服务器资源
但是在单页面应用当中,页面的主要内容不会重新加载,而是通过JavaScript动态地替换部分内容,从而提供了更快的响应速度和更流畅的用户体验。
这个哈希路由就是一个锚点
举个例子!
在某篇文章中,其右边的目录就运用了哈希路由
例如我们点击它的结语,页面就会跳到这个部分,
并且URL改变为
其URL内的Hash
字段则会修改,Hash
字段就是URL中带#
后的内容
修改后,页面并不加载,而是跳转到定义的锚点,这个锚点就是哈希路由,而在这个URL中,它的结语
的哈希路由为heading-5
现在你明白什么是哈希路由(Hash Router)了吗
我们现在就来探究一下,这样一个锚点是如何实现的
先设置三个导航栏
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>手写Hash Router</title> </head> <body> <nav id="nav"> <ul> <li><a href="#/page1">page1</a></li> <li><a href="#/page2">page2</a></li> <li><a href="#/page3">page3</a></li> </nav> <div id="container"></div> </body> </html>
我们使用<a>
标签来分别指向三个页面的URL,#
就代表着URL的哈希字段,点击这三个标签就会分别跳转这三个锚点。
还定义了一个container
,用来放显示的界面,就像Vue中的<router-view>
接下来我们通过JS来实现——锚点时空跳跃
也就是说,当我们跳转至#/page1
时,page1就要放进container中
我们跳转至#/page1
时,page1就要放进container中
开始动手!
我们先定义一个实现路由类:
class HashRouter{}
再写一个构造函数,定义一个变量routes
来保存路由规则,再添加一个事件监听,监听hashchange
事件,一旦hash值改变,就调用load
方法。
constructor() { this.routes = {}; // 创建一个对象来存储路由规则 window.addEventListener('hashchange', this.load.bind(this), false); // 当URL的hash部分发生变化时,调用load方法 }
我们再写两个函数,将各页面导入进HTML的方法使用routes
对象通过数组绑定,也就是注册路由规则
register (hash, callback = function() {}) { this.routes[hash] = callback; // 注册路由规则,将hash和对应的回调函数存储在routes对象中 } registerIndex(callback = function() {}) { this.routes['index'] = callback; // 注册默认路由,当hash为空时使用 }
接下来我们来写load
方法,
先从location.hash
获取当前URL的哈希部分。由于哈希总是以#
开始,所以使用slice(1)
来去除这个字符,得到实际的哈希值字符串。
再根据hash
的值,load
方法会从this.routes
对象中查找对应的处理器。如果hash
为空,意味着URL中没有特定的哈希值,这时会使用默认的index
处理器,即通过registerIndex
方法注册的回调函数。如果hash
有值,它会尝试作为键在routes
对象中查找对应的处理器。
简单来说,如果URL中有hash
字段则调用该页面的方法使该页面展示,如果没有就展示首页
load() { let hash = location.hash.slice(1); // 去掉hash前缀'#",获取当前hash值 let handler; if(!hash) { // 如果hash为空,则使用默认路由 handler = this.routes['index']; } else { // 否则根据hash值找到对应的handler handler = this.routes[hash]; } handler && handler.call(this); // 执行找到的handler,如果没有找到则不执行任何操作 }
最后我们创建一个实例对象,再获取container
元素
let router = new HashRouter(); // 创建一个HashRouter实例 let container = document.getElementById('container'); // 获取页面上的容器元素
我们将三个页面事件和首页与实例对象内的routes
对象进行路由规则注册
// 注册不同的路由规则 router.registerIndex(() => container.innerHTML = '我是首页'); router.register('/page1', () => container.innerHTML = '我是Page1'); router.register('/page2', () => container.innerHTML = '我是Page2'); router.register('/page3', () => container.innerHTML = '我是Page3');
最后加载路由规则
router.load(); // 加载当前的路由规则
于是我们的手写哈希路由就完成了
点击page1
完整js代码
class HashRouter{ constructor() { this.routes = {}; // 创建一个对象来存储路由规则 window.addEventListener('hashchange', this.load.bind(this), false); // 当URL的hash部分发生变化时,调用load方法 } register (hash, callback = function() {}) { this.routes[hash] = callback; // 注册路由规则,将hash和对应的回调函数存储在routes对象中 } registerIndex(callback = function() {}) { this.routes['index'] = callback; // 注册默认路由,当hash为空时使用 } load() { let hash = location.hash.slice(1); // 去掉hash前缀'#",获取当前hash值 let handler; if(!hash) { // 如果hash为空,则使用默认路由 handler = this.routes['index']; } else { // 否则根据hash值找到对应的handler handler = this.routes[hash]; } handler && handler.call(this); // 执行找到的handler,如果没有找到则不执行任何操作 } } let router = new HashRouter(); // 创建一个HashRouter实例 let container = document.getElementById('container'); // 获取页面上的容器元素 // 注册不同的路由规则 router.registerIndex(() => container.innerHTML = '我是首页'); router.register('/page1', () => container.innerHTML = '我是Page1'); router.register('/page2', () => container.innerHTML = '我是Page2'); router.register('/page3', () => container.innerHTML = '我是Page3'); router.load(); // 加载当前的路由规则
总结
哈希路由是一种实用的技术,它使得SPA能够在不重新加载整个页面的情况下实现页面内容的动态更新,从而提高了应用的性能和用户体验。