frontend-notes

Hash路由和History路由

什么是 SPA

SPA 是 single page web application 的简称,译为单页Web应用。

SPA 就是一个 WEB 项目只有一个 HTML 页面,一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转。 取而代之的是利用 JS 动态的变换 HTML 的内容,从而来模拟多个视图间跳转

什么是前端路由

简单的说,就是在保证只有一个 HTML 页面,且与用户交互时不刷新和跳转页面的同时,为 SPA 中的每个视图展示形式匹配一个特殊的 url。在刷新、前进、后退和SEO时均通过这个特殊的 url 来实现。

路由需要实现三个功能:

接下来要介绍的 hash 模式和 history 模式,就是实现了上面的功能

Hash路由和History路由区别

演示

//http://127.0.0.1:8001/01-hash.html?a=100&b=20#/aaa/bbb
location.protocal // 'http:'
localtion.hostname // '127.0.0.1'
location.host // '127.0.0.1:8001'
location.port //8001
location.pathname //'01-hash.html'
location.serach // '?a=100&b=20'
location.hash // '#/aaa/bbb'

模拟实现

以下代码拷贝至面试官: 你了解前端路由吗?

Hash路由

在线例子 ```js class Routers { constructor() { // 储存hash与callback键值对 this.routes = {}; // 当前hash this.currentUrl = ‘’; // 记录出现过的hash this.history = []; // 作为指针,默认指向this.history的末尾,根据后退前进指向history中不同的hash this.currentIndex = this.history.length - 1; this.refresh = this.refresh.bind(this); this.backOff = this.backOff.bind(this); // 默认不是后退操作 this.isBack = false; window.addEventListener(‘load’, this.refresh, false); window.addEventListener(‘hashchange’, this.refresh, false); }

route(path, callback) { this.routes[path] = callback || function() {}; }

refresh() { this.currentUrl = location.hash.slice(1) || ‘/’; if (!this.isBack) { // 如果不是后退操作,且当前指针小于数组总长度,直接截取指针之前的部分储存下来 // 此操作来避免当点击后退按钮之后,再进行正常跳转,指针会停留在原地,而数组添加新hash路由 // 避免再次造成指针的不匹配,我们直接截取指针之前的数组 // 此操作同时与浏览器自带后退功能的行为保持一致 if (this.currentIndex < this.history.length - 1) this.history = this.history.slice(0, this.currentIndex + 1); this.history.push(this.currentUrl); this.currentIndex++; } this.routesthis.currentUrl; console.log(‘指针:’, this.currentIndex, ‘history:’, this.history); this.isBack = false; } // 后退功能 backOff() { // 后退操作设置为true this.isBack = true; this.currentIndex <= 0 ? (this.currentIndex = 0) : (this.currentIndex = this.currentIndex - 1); location.hash = #${this.history[this.currentIndex]}; this.routesthis.history[this.currentIndex]; } }


### History路由
> [在线例子](https://codepen.io/xiaomuzhu/pen/QmJorQ/)
```js
class Routers {
  constructor() {
    this.routes = {};
    // 在初始化时监听popstate事件
    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]();
    });
  }
}

参考