ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # 摘要 无论是 vue-router 还是 react-router,其核心都是用 hash / H5 history 实现的,这里我们抛开框架来自己实现下简单的前端路由功能。 # hash 路由 hash 路由一个明显的标志是带有`#`,我们主要是通过监听 url 中的 hash 变化来进行路由跳转。 有以下几个要点: - 以键值对的形式存储 path 及其回调函数 - 监听 hashchange 事件触发对应的回调 - 用一个 history 数组来记录之前的 hash 路由,并创建一个指针来实现前进后退的功能 ```js class Routers { constructor () { // 以键值对的形式存储路由 this.routes = {} // 当前路由的 url this.currentUrl = '' // 记录出现过的 hash this.history = [] // 作为指针,默认指向 this.history 的末尾,根据后退前进指向 history 中不同的 hash this.currentIndex = this.history.length - 1 this.isBack = false // 记录是否为后退操作 // 监听对应事件 this.refresh = this.refresh.bind(this) this.backOff = this.backOff.bind(this) window.addEventListener('load', this.refresh, false) window.addEventListener('hashchange', this.refresh, false) } // 将 path 路径与对应的 callback 函数储存 route (path, callback) { this.routes[path] = callback || function () {} } // 刷新 refresh () { this.currentUrl = location.hash.slice(1) || '/' // 获取当前 URL 中的 hash 路径 if (!this.isBack) { this.history.push(this.currentUrl) // 将当前 hash 路由推入 history 数组中 } this.currentIndex++ // 指针向前移动 this.routes[this.currentUrl]() // 执行当前 hash 路径的 callback 函数 this.isBack = false } // 后退功能 backOff () { this.isBack = true // 如果指针小于 0 的话就不存在对应 hash 路由了,因此锁定指针为 0 即可 this.currentIndex <= 0 ? this.currentIndex = 0 : this.currentIndex = this.currentIndex - 1 location.hash = `#${this.history[this.currentIndex]}` // location 响应变化 this.routes[this.history[this.backOff.currentIndex]]() // 执行对应的 callback } } ``` # History 路由 首先 History 有以下 API,具体见 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/History) | 属性 | 描述 | | --- | --- | | state -> window.history.state | 返回一个表示历史堆栈顶部的状态的值 | | length -> window.history.length | 返回一个整数,表示会话历史中的元素数目 | 方法 | 描述 | | --- | --- | | back() | 返回上一页 | | forward() | 在浏览器历史记录中前往下一页 | | go() | 参数为 -1 时前往上一页,参数为 1 时前往下一页 | | pushState(stateObject, title, URL) | 按指定的名称和 URL(如果提供该参数)将数据 push 进会话历史栈,数据被 DOM 进行不透明处理;你可以指定任何可以被序列化的 javaScript 对象 | | replaceState(stateObject, title, URL) | 按指定的数据、名称和 URL(如果提供该参数)更新历史栈上最新的入口。这个数据被 DOM 进行了不透明处理。你可以指定任何可以被序列化的 JavaScript 对象 | | 事件 | 描述 | | --- | --- | | popState | 浏览器跳转到新的状态时会触发 popState 事件,该事件将携带这个 stateObject 参数的副本 | ```js class Routers { constructor () { this.routes = {} this._bindPopState() } // 初始化路由 init (path) { history.replaceState({ path: path }, null, path) this.routes[path] && this.routes[path]() } // 将路径和对应的回调函数加入 hashMap route (path, callback) { this.routes[path] = callback || function () {} } go (path) { history.pushState({ path: path }, null, path) this.routes[path] && this.routes[path]() } // 监听 popstate 事件 _bindPopState () { window.addEventListener('popstate', e => { const path = e.state && e.state.path this.routes[path] && this.routes[path]() }) } } ``` # 参考资料 [https://www.cxymsg.com/guide/router.html#%E5%89%8D%E8%A8%80](https://www.cxymsg.com/guide/router.html#%E5%89%8D%E8%A8%80)