[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)
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令