HashRouter 与 HistoryRouter 的简单实现

1,894 阅读1分钟

最近在看 vue-router ,关于 vue-router 的一些分析可以看文章 vue-router源码分析 ,我们们都知道 vue-router 拥有 hash/history/abastract 三种模式,其中 abstract 主要运用于 SSR, 本文主要讲述一些hash/history模式的简单实现

HistoryRouter

说到 History 路由就不得不提到 history 的 pushStatereplaceState 方法,这两个 API 都可以改变浏览器的路径而不进行实际的页面跳转,被大量用来实现各种 SPA 框架

History大致实现如下

class HistoryRouter{
    constructor(){
      this._routes = {};
      this._history = window.history
      window.addEventListener('popstate',e => {
        console.log(e)
      })
    }
    addRoute(path,callback){
      this._routes[path] = callback
    }
    push(path){
      this._history.pushState({path},"",path)
      this._routes[path] && this._routes[path]()
    }
    replace(path){
      this._history.replaceState({path},"",path)
      this._routes[path] && this._routes[path]()
    }
}

HistoryRouter 暴露三个 API 负责 路由的添加与跳转

HashRouter

hash 模式也是大家常用的一种模式了,它利用路由的 hash 来控制路由的跳转。 hash 模式相较于 history 模式更为复杂,大致实现如下

class HashRouter{
    constructor(){
        this.history = window.history
        this.support = !!this.history.pushState
        this.routes = {}
        window.location.hash = ''
        window.addEventListener(this.support?'popstate':'hashchange',e => {
            console.log(e)
        })
    }
    addRoute(path,callback){
        this.routes[path] = callback || function(){}
    }
    push(path){
        if(this.support){
            this.history.pushState({path},'',this.getUrl(path))
        }else{
            window.location.hash = path
        }
        this.routes[path]()
    }
    replace(path){
        if(this.support){
            this.history.replaceState({path},'',this.getUrl(path))
        }else{
            window.location.hash = path
        }
        this.routes[path]()
    }
    getUrl(path){
        return `#${path}`
    }
}

这里参考了 vue-router的实现,先去判断浏览器是否支持 history.pushstate ,如果支持则使用pushState/replaceState 否则使用 window.location.hash 进行 hash 的拼接

Hash模式与History模式的一些问题

  • History 模式丢掉了丑陋的 # ,比较美观
  • 使用 Hash 模式容易与锚点混淆
  • 使用 History 模式时因为使用的是真实的url,当你刷新时会向后端请求产生404