自己动手实现个SPA应用的hash路由

233 阅读1分钟

hash 介绍

我们在使用 Vue 或者 React 等前端渲染时,通常会有 hash 路由和 history 路由两种路由方式。

hash的优缺点

优点:

  • 只需要前端配置路由表, 不需要后端的参与
  • 兼容性好, 浏览器都能支持
  • hash值改变不会向后端发送请求, 完全属于前端路由

缺点:

  • hash值前面需要加#, 不符合url规范,也不美观
  • 服务器端无法准确跟踪前端路由信息
  • 与锚点定位元素的功能冲突

通过Hash实现前端路由

监听 url 中 hash 的变化,会触发hashchange事件,我们可以在监听事件中渲染不同的内容,从而实现前端路由。

先声明个 Router

class Router {
  constructor(params) {
    this.cache = params.router;
    this.init();
  }

  //初始化 添加监听浏览器hashchange 以及dom loaded函数
  init() {
    window.addEventListener('hashchange', () => {
      this.trigger();
    });
    window.addEventListener('load', () => {
      this.trigger();
    })
  };

  //匹配hash对应的回调函数,并触发
  trigger() {
    const hash = location.hash.slice(1) || 'default';
    const cache = this.cache;
    for (const r in cache) {
      if (cache.hasOwnProperty(r)) {
        const reg = this.initRegexps(r);
        if (reg.test(hash)) {
          document.getElementById('app').innerHTML = cache[r]
        }
      }
    }

  };

  /**
   *将cache内的key 做正则处理,并返回
   * 第一个正则 匹配诸如/,.+-?$#{}[]] 关键字  并在关键字前面加转译字符\
   * 第二个正则 匹配() 标示()内部内容可有可无
   * 第三个正则 匹配: 在/后面可以由接受任意字符,直到遇到下一个/
   * 第四个正则 匹配* 在*后面可以由接受任意字符
   */
  initRegexps(route) {
    route = route.replace(/[/,.+\-?$#{}\[\]]/g, '\\$&')
        .replace(/\((.*?)\)/g, '(?:$1)?')
        .replace(/(\/\w?:\w+)+/g, '\/([^/]+)')
        .replace(/\*\w*/g, '([^?]*?)');

    return new RegExp('^' + route + '$');
  };

  //将匹配的正则返回,为回调函数提供参数
  getParams(reg, hash) {
    return reg.exec(hash).slice(1);
  }
}

在html上

<!--菜单区域-->
<div>
    <a href="#/index">index</a>
</div>
<div>
    <a href="#/det">det</a>
</div>
<!--显示内容区-->
<div id="app"></div>

配置router并触发。

const router = {
    "/index": '<div>index内容</div>',
    "/det": '<div>det内容</div>'
  }
  new Router({
    router,
    templateId: 'app'
  });