HTML 面试要点:History 和 Hash 路由方式

2023-05-17 16:07:34 浏览数 (2)

# 为什么要使用路由

越来越多的应用使用 Ajax 请求数据,浏览器 URL 不会发生任何变化。同时,浏览的页面内容在用户下次使用 URL 访问时将无法重新呈现,使用路由可以很好地解决这个问题。

单页面利用了 JavaScript 动态变换网页内容,避免了页面重新加载;路由这提供了浏览器地址变化,网页内容页跟随变化,两个结合提供了体验良好的 单页面应用。

# 前端路由实现方法

路由需要实现以下功能:

  1. 当浏览器地址变化时,切换页面;
  2. 点击浏览器【后退】、【前进】按钮时,网页内容跟随变化;
  3. 刷新浏览器,网页加载当前路由对应的内容。

在单页面 web 网页中,单纯的浏览器地址改变,网页不会重载,如单纯的 hash 网址改变网页不会变化,因此路由主要通过监听事件,并利用 JavaScript 实现动态改变网页内容,有以下实现方法:

  • hash 模式: 监听浏览器地址 hash 值变化,执行相应的 JavaScript 切换网页
  • history 模式:利用 history API 实现 URL 变化,网页内容跟随变化

二者的区别是 hash 会在浏览器地址后面增加 #,而 history 可以自定义地址。

# hash 模式

使用 window.location.hash 属性及窗口的 onhashchange 事件 (opens new window),可以实现监听浏览器地址 hash 值变化,执行相应的 JavaScript 切换网页。一些需要注意的地方:

  • hash 指地址中 # 以及后面的字符,也叫散列值
    • 也叫 锚点,本身是用来做页面跳转定位的,如 https://cellinlab.xyz/#/home 的 hash 即 #/home
  • 散列值不会随请求发送到服务器端,所以改变 hash,不会重新加载页面
  • 监听 windowhashchange 事件,当散列值改变时,可以通过 location.hash 来获取和设置 hash 值
  • location.hash 值的变化会直接反应到浏览器的地址栏

# 触发 hashchange 的情况

  • 浏览器地址散列值的变化(包括浏览器的前进、后退)会触发 window.location.hash 值的变化,从而触发 onhashchange 事件
  • 当浏览器地址栏中 URL 包含 哈希 如 https://cellinlab.xyz/#/home,此时按下回车,浏览器发送 https://cellinlab.xyz/ 请求到服务器,请求完毕之后设置散列值为 #/home,此时触发 onhashchange 事件
  • 当值改变浏览器地址栏 URL 的哈希部分,按下回车,浏览器不会发送任何请求到服务器,只是设置散列值修改,并触发 onhashchange 事件
  • html<a> 标签的属性 href 可以设置为页面的元素 ID 如 #top,当点击链接时页面跳转到该 ID 元素所在区域,同时浏览器自动设置 window.location.hash 属性,地址栏中的哈希值也会发生变化,并触发 onhashchange 事件
代码语言:javascript复制
window.location.hash = 'home';
let hash = window.location.hash; // '#home'

window.addEventListener('hashchange', function () {
  console.log('hashchange');
});

# history 模式

# 概述

  • window.history 属性指向 History 对象 (opens new window),它表示当前窗口的浏览历史,当发生改变时,只会改变页面的路径,不会刷新页面
  • History 对象保存了当前窗口访问过的所有页面网址,可以通过 history.length 获知当前窗口访问过的页面数量
  • 由于安全原因,浏览器不允许脚本读取这些地址,但允许在地址之间跳转
  • 浏览器工具栏的 “前进” 和 “后退” 按钮,其实就是对 History 对象进行操作

# 属性

History 对象主要有两个属性:

  • History.length 当前窗口访问过的页面数量(含当前页面)
  • History.state History 堆栈最上层的状态值
代码语言:javascript复制
history.length; // 1

history.state; // undefined

# 方法

  • History.back() 移动到上一个网址,相当于点击浏览器后退键,该方法对于第一个访问的页面无效
    • 注意移动到以前访问的页面时,页面通常是从浏览器缓存中加载,而不是重新请求服务器发送新的网页
  • History.forward() 移动到下一个网址,相当于点击浏览器前进键,该方法对于最后一个访问的页面无效
  • History.go() 接收一个整数作为参数,以当前网址为基准,移动到参数指定的网址
    • 如果参数超过实际存在的网址范围,该方法无效果
    • 如果不指定参数,默认参数为 0,相当于刷新当前
代码语言:javascript复制
history.back();
history.forward();
history.go(1); // 相当于 history.forward()
history.go(-1); // 相当于 history.back()
history.go(0); // 相当于刷新当前页面

History.pushState() 用于在历史中添加一条记录

  • pushState() 不会触发页面刷新,只是导致 History 对象发生变化,地址栏会有变化
  • history.pushState(obj, title, url)
    • obj 一个对象,通过 pushState 可以将该对象内容传递到新页面中,不需要是可以填 null
    • title 指标题,但多数浏览器不支持,建议传空字符串
    • url 新的网址,必须与当前页面处于同一个域,不指定的话则为当前路径,如果设置一个跨域网址会报错
代码语言:javascript复制
const data = { foo: 'bar' };
history.pushState(data, '', '/about.html');
console.log(history.state); // { foo: 'bar' }

  • 注意:如果 pushState 的 URL 参数设置了一个新的锚点值(即 hash),并不会触发 hashchange 事件。相反,如果 URL 的锚点值变了,会在 History 对象创建一条浏览记录。
  • 如果 pushState() 方法设置了一个跨域网址,会报错

History.replaceState() 用来修改 History 对象的当前记录,用法与 pushState 相同

popstate() 每当 History 对象出现变化时,就会触发 popstate 事件

  • 仅仅调用 pushState() 方法或 replaceState() 方法,并不会触发该事件
  • 只有用户点击浏览器倒退按钮或前进按钮,或者使用 JavaScript 调用 history.back()history.forward()history.go() 方法,才会触发该事件
  • 该事件只针对同一个文档,如果浏览历史的切换导致加载不同的文档,该事件不会触发
  • 页面第一次加载时,浏览器不会触发 popstate 事件

0 人点赞