js

零、引言
  本篇是关于 window.location (history/hash) 的尝试,算是为了学习各种 router 的基础吧。

  参考资料:
    1. url 中的 hash;
 

一、基础准备

  基础的 index.html 页面。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>js - router</title>
</head>
<body>
  <ul>
    <!-- 定义路由 -->
    <li><a href="#/home">home</a></li>
    <li><a href="#/about">about</a></li>

    <!-- 渲染路由对应的 UI -->
    <div id="routeView"></div>
  </ul>

  <!-- 不同场景下引入对应文件 -->
  <!-- <script src="hash.js"></script> -->
  <!-- <script src="history.js"></script> -->
</body>
</html>

二、hash(#)

  最开始是用在 a 标签的 href 中,用来跳转到页面的指定位置,当然,因为经常与 id 选择器一起使用,所以一开始经常认为单纯的是 id 选择器。在 H5 更新的标准中,它有了更多的意义。
上面参考资料中提及的需要注意的地方是 4.5.7 三点,因此也有了我们接下来的实践:
// 维护 UI 页面
let routerView = null;

// 路由变化时,根据路由渲染对应的 ui 页面
function onHashChange() {
  switch (window.location.hash) {
    case '':
    case '#/home':
      routerView.innerHTML = 'Home';
      return ;
    case '#/about':
      routerView.innerHTML = 'About';
      break;
    default:
      break;
  }
}

// 页面加载完不会触发 hashchange,这里主动触发一次 hashchange 事件。
window.addEventListener('DOMContentLoaded', () => {
  routerView = document.querySelector('#routeView');
  onHashChange();
})

// 监听路由变化。
window.addEventListener('hashchange', onHashChange);

三、history

  history 在 H5 标准中新增了 pushState/replaceState 两个 api,这两均能够修改浏览器的历史记录,同时也方便了在写代码的过程中对页面流向的控制,不过也存在些问题,下一个章节进行比较。
先看实践:
// 维护 UI 页面。
let routerView = null;

// 路由变化时,根据路由渲染对应 UI 页面。
function onPopState() {
  switch (window.location.pathname) {
    case '/':
    case '/home':
      routerView.innerHTML = 'Home';
      return ;
    case '/about':
      routerView.innerHTML = 'About';
      break;
    default:
      break;
  }
}

// 页面加载完不会触发 onPopState, 这里主动触发一次 onPopState 事件。
window.addEventListener('DOMContentLoaded', () => {
  routerView = document.querySelector('#routeView');
  // 刷新页面。
  onPopState();

  // 拦截 <a> 标签点击事件默认行为, 点击时使用 pushState 修改 URL并更新手动 UI,从而实现点击链接更新 URL 和 UI 的效果。
  let links = document.querySelectorAll('a[href]');
  links.forEach(el => {
    el.addEventListener('click', e => {
      e.preventDefault();
      // 手动拦截
      window.history.pushState(null, '', el.getAttribute('href'));
      onPopState();
    })
  })
})

// 监听路由变化。
window.addEventListener('popstate', onPopState);
和 hash 的处理思路相同,调用的 api 略有区别,增加了取消 DOM 元素的原生事件步骤。
 

四、两者的特点

  1. hash -- 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。比如这个 URL:http://www.abc.com/#/hello,hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
  2. history -- 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
 
  所以呢, 在 hash 模式下,无论怎么刷新网页,浏览器一直是请求的同一个 index.html 文件,所以服务器不需要做额外的处理,只是显示在 url 栏中不那么美观。但是在 history 模式下,前进/后退等操作也只是修改的本地浏览器的历史栈,不发请求,刷新就不同了,这个操作会实打实地去请求当前 url 对应的资源,这意味着服务器不做处理,分分钟是 404,因此 vue-router 文档中强调开启 history 需要服务器支持。
 
原文地址:https://www.cnblogs.com/cc-freiheit/p/12966157.html