前端路由hash、history的实现

前言

这个坑,已经埋在笔者的待办事项里很久,就好比一滴酱油滴在白色的桌子上,现在有时间了,很想把它“擦掉”

正文

前端路由实现有两种,一是 hash,另一种是 histroy。

hash 原本是为了定位,笔者印象中最开始是 PC 端商城的楼层,点击跳转到某一模块

history 是 HTML5 新出的 API,它属于 bom。通过 history 对象可以操作浏览器的会话历史以及向前向后跳转

笔者是 React 开发者,Vue 好久没用了,所以以下内容是以 React 的角度描写

前端开发——React 全家桶——路由采用第三方库 react-router 和—— react-router 的底层是 history

我们在写 react 的路由写法时,通常为两种,hash 和 history ,使用它的本质是 history 库

笔者在这里写个简单的

hash 模式

它的本质是通过监听hash变化事件来修改路由内容

<body>
  <a href="#/home">Home</a>
  <a href="#/user">User</a>
  <a href="#/about">About</a>
  <div id="view"></div>
</body>
<script>
  function onHashChange() {
    const view = document.getElementById("view");
    switch (location.hash) {
      case "#/home":
        view.innerHTML = "Home";
        break;
      case "#/user":
        view.innerHTML = "User";
        break;
      case "#/about":
        view.innerHTML = "About";
        break;
      default:
        view.innerHTML = "Home";
        break;
    }
  }
  window.addEventListener("hashchange", onHashChange);
</script>

hash模式

history 模式

看了 hash 模式,我们会觉得很简单,无非是监听 hash 的变化,现在我们再看 history 模式

<body>
  <a href="/home">Home</a>
  <a href="/user">User</a>
  <a href="/about">About</a>
  <div id="view"></div>
</body>
<script>
  const elements = document.querySelectorAll("a[href]");
  elements.forEach((el) =>
    el.addEventListener("click", (e) => {
      e.preventDefault();
      const test = el.getAttribute("href");
      history.pushState(null, null, el.getAttribute("href"));
      onPopState();
    })
  );

  function onPopState() {
    const view = document.getElementById("view");
    switch (location.pathname) {
      case "/home":
        view.innerHTML = "Home";
        break;
      case "/user":
        view.innerHTML = "User";
        break;
      case "/about":
        view.innerHTML = "About";
        break;
      default:
        view.innerHTML = "Home";
        break;
    }
  }
  window.addEventListener("popstate", onPopState);
</script>

无非是把 hashchange 改成了 popstate,当 history 对象变化时,会出发 onPopState 事件,而我们的 history 模式不想 hash 模式那样,点击hash 对象时(#xx)会自动监听,所以我们遍历监听路由点,点击时实现和 hash 一样的模式,即点击时往历史中添加一条记录

线上demo: