路由模式hash | history

109 阅读1分钟

Vue-Router有两种模式:hash模式history模式。默认的路由模式是hash模式。

hash模式

特点: hash值会出现在URL里面,但是不会出现在HTTP请求中,对后端完全没有影响。hash值变化对应的URL都会被浏览器记录下来,这样浏览器就能实现页面的前进和后退。虽然是没有请求后端服务器,但是页面的hash值和对应的URL关联起来了。

原理: hash模式的主要原理就是window对象上的onhashchange()事件

模拟hash模式下单页页面应用

<body>
  <ul>
    <li><a href="#/home">首页</a></li>
    <li><a href="#/about">关于</a></li>
  </ul>

  <div id="routeView"></div>
  <script>
    const routes = [
      {
        path: "/home",
        component: `<div class='home-page'>首页</div>`,
      },
      {
        path: "/about",
        component: `<div class='about-page'>关于页面</div>`,
      },
      {
        path: "/:pathMatch(.*)",
        component: `<div class='not-found'>404页面</div>`,
      },
    ];

    // 初始化时执行
    window.addEventListener("DOMContentLoaded", onHashChange);
    window.addEventListener("hashchange", onHashChange);

    function onHashChange() {
      let findRoute = routes.find(
        (route) => `#${route.path}` === location.hash
      );
      if (!findRoute) {
        findRoute = routes[routes.length - 1];
      }
      document.querySelector("#routeView").innerHTML = findRoute.component;
    }
  </script>
</body>

history模式

特点: 当使用history模式时,URL就像这样:abc.com/user/id。相比hash模式更加好看。但是,history模式下,获取页面资源时,会拼接url中的pathname(/user/id)作为整体请求,如果后台没有正确配置(譬如ngnix设置location重定向),访问时会返回404。另外浏览器前进后退时,也需要监听popstate特殊处理,否则无法管理到具体页面。

原理: 运用history对象上的 pushState() 和 replaceState() 方法,提供了对历史记录进行修改的功能,虽然修改了url,但浏览器不会立即向后端发送请求;浏览器前进后退时,也需要监听window对象上的popstate特殊处理。

模拟 history模式下单页页面应用

<body>
  <ul>
    <li><a href="/home">首页</a></li>
    <li><a href="/about">关于</a></li>
  </ul>

  <div id="routeView"></div>
  <script>
    const routes = [
      {
        path: "/home",
        component: `<div class='home-page'>首页</div>`,
      },
      {
        path: "/about",
        component: `<div class='about-page'>关于页面</div>`,
      },
      {
        path: "/:pathMatch(.*)",
        component: `<div class='not-found'>404页面</div>`,
      },
    ];

    window.addEventListener("DOMContentLoaded", onLoad);
    // 浏览器的前进后退
    window.addEventListener("popstate", renderComponent);

    function onLoad() {
      const links = document.querySelectorAll("li a"); // 获取所有的li下的a标签
      links.forEach((a) => {
        a.addEventListener("click", (e) => {
          e.preventDefault(); // 阻止a的跳转行为
          history.pushState(null, "", a.getAttribute("href"));
          // 映射对应的dom
          renderComponent();
        });
      });
    }

    function renderComponent() {
      let findRoute = routes.find(
        (route) => `${route.path}` === location.pathname
      );
      if (!findRoute) {
        findRoute = routes[routes.length - 1];
      }
      document.querySelector("#routeView").innerHTML = findRoute.component;
    }
  </script>
</body>