《揭秘 Hash 路由:源码实现的优雅之道》
前言
在当今互联网应用的蓬勃发展中,路由技术成为了构建流畅用户体验的关键要素之一。Hash 路由作为一种常见且实用的路由方式,以其独特的特性在众多前端框架和应用中发挥着重要作用。 在接下来的篇章中,我们将深入探索 Hash 路由源码的实现,揭开其神秘的面纱,一同领略其中的精妙之处。
代码
<!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>
<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>
</ul>
</nav>
<!-- router-view -->
<div id="container"></div>
<script>
// 接下来是 JavaScript 部分的代码
</script>
</body>
</html>
在 <body> 标签内,我们有一个导航栏 <nav> ,其中包含一个无序列表 <ul> ,列表中的每个项目都是一个链接。这些链接的 href 属性使用了 hash 值(例如 #/page1 、#/page2 、#/page3 )来指定不同的页面路径。
然后是一个 id 为 container 的 <div> 元素,它将用于动态显示根据路由变化加载的内容。
接下来看 JavaScript 部分的代码:
// 定义了一个名为 HashRouter 的类
class HashRouter {
constructor() {
// 初始化一个空的对象 routes,用于存储路由和对应的回调函数
this.routes = {};
// 为 window 对象添加 'hashchange' 事件的监听器,当哈希值变化时调用 this.load.bind(this) 函数
window.addEventListener("hashchange", this.load.bind(this), false);
}
register(hash, callback) {
// 用于注册路由和对应的回调函数
this.routes[hash] = callback;
}
load() {
// 打印当前页面的哈希值
console.log(location.hash);
// 去除哈希值开头的 '#' 符号,得到实际的路由部分
let hash = location.hash.slice(1);
console.log(hash, "///");
// 初始化一个变量 hander,用于后续存储对应的回调函数
let hander;
// 如果哈希值为空,即没有指定具体路由,将 hander 赋值为 routes 对象中 'index' 对应的回调函数
if (!hash) {
hander = this.routes["index"];
} else {
// 否则,将 hander 赋值为 routes 对象中与当前哈希值对应的回调函数
hander = this.routes[hash];
}
// 如果 hander 存在,使用 call 方法以当前对象为 this 上下文调用该回调函数
hander && hander.call(this);
}
registerIndex(callback = function () {}) {
// 用于注册首页的回调函数
this.routes["index"] = callback;
}
}
// 创建 HashRouter 类的实例 router
let router = new HashRouter();
// 获取页面中 id 为 'container' 的元素
let container = document.getElementById("container");
// 注册首页的回调函数,该函数将 '我是首页' 赋值给 container 的 innerHTML
router.registerIndex(() => (container.innerHTML = "我是首页"));
// 注册 '/page1' 路由的回调函数,该函数将 '我是 page1' 赋值给 container 的 innerHTML
router.register("/page1", () => (container.innerHTML = "我是page1"));
// 注册 '/page2' 路由的回调函数,该函数将 '我是 page2' 赋值给 container 的 innerHTML,并打印 this 和 routes 对象
router.register("/page2", function () {
container.innerHTML = "我是page2";
console.log(this, this.routes);
});
// 注册 '/page3' 路由的回调函数,该函数将 '我是 page3' 赋值给 container 的 innerHTML
router.register("/page3", () => (container.innerHTML = "我是page3"));
// 打印 router 对象的 routes 属性
console.log(router.routes);
// 调用 load 方法进行初始加载
router.load();
创建类的实例,调用类中的register和registerIndex存储方法,有哈希值的调用register,没有hash调用registerIndex作为首页,当监听时间发现hash值有变化那就执行this.load.bind(this),指定函数内部的 this 值为本实例对象,并且执行load方法,实现跳转并且执行了注册方法。