前端路由你现在还不会?详解hash模式与history模式原理

导读

在很久以前,每次切换 url 浏览器整个页面都会刷新一次。有时候只是想切换一点内容,url 也变变化了,那整个浏览器页面也跟着变了,体验非常不好。但是随着技术的进步,出现了 AJAX技术,AJAX 可以让网页的页面局部内容更新,url 可以保持不变。但是这个时候又发现一个问题,我页面利用 AJAX 更新的内容。我重新刷新浏览器,内容又重新变回了老样子。为了解决这个问题,出现了单页面应用。

什么叫单页面应用?其实就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。只需观察路由(url 连接)变化,我就切换这个页面的内容,不需要页面重新刷新,用户体验更好。实现这个路由功能,就需要这2种路由的模式:hash 模式与 history 模式。

在这里插入图片描述

单页面路由实现功能

在实现这个路由,我们需要考虑3种情况。

1.输入 url 能切换页面

2.浏览器前进与后退按钮,可以对应切换页面

3.浏览器刷新,页面加载内容与原来一样

实现浏览器只需刷新一次,然后根据 url 的变化,切换页面功能。那我们需要利用 js 事件监听 url 变化。那如何监听 url 变化呢?那我们下面来讲2种路由的模式:hash 模式与 history 模式。

hash 模式

监听浏览器 url 上的 hash 值,切换浏览器对应的页面。

什么是 hash 值?hash 值是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。可以通过 window.location.hash 获取。举个例子: www.baidu.com/#home。 那这个 hash 值就是 #home 了。

hase 模式与 history 模式明显的区别就是 url 上 锚点(#)符号

那我们可以利用 浏览器事件 onhashchange 事件监听 url(window.location.hash ) 变化 ,切换不同页面,执行对应页面的js。需要注意几点:

  1. hash 值指的是地址中#号以及后面的字符,也称作锚点或散列值
  2. hash 值不会发送到服务器,改变 hash 值浏览器不会重新加载
  3. location.hash 值的变化会直接反应到浏览器地址栏

触发 hashchange 几种情况:

  1. url 上 hash 值的变化,都会触发 hashchange 变化
  2. 当 url 地址中有 hash 值,输入浏览器 www.baidu.com/#home,先请求服务器 www.baidu.com,然后浏览器再触发 onhashchange 事件
  3. html中 <a> 标签的属性 href 可以设置为页面的元素ID如 #top,当点击该链接时页面跳转至该id元素所在区域,同时浏览器自动设置 window.location.hash 属性,地址栏中的 hash 值也会发生改变,并触发 onhashchange 事件

总结: 只要浏览器 url 中带有 # 号,并且 hash 变化了,都会触发 onhashchange 事件。

模拟一下对应原理:

<style>
    div {
        display: none;
    }
</style>
<!-- home、community、user、404表示4个不同页面 -->
<div class="home">首页</div>
<div class="community">社区</div>
<div class="user">我的</div>
<div class="error">404</div>
// 监听 hash 变化,点击浏览器的前进后退会触发
window.addEventListener('hashchange', function () {
    // 获取 hash 值,不包括#号,例如:www.baidu.com/#home,获取到 home 字符串标识
    var hashVal = window.location.hash.split('#')[1];
    // 获取对应页面的标识
    var showPage = document.querySelector('.' + hashVal);
    // 根据 hash 值变化,展示不同页面内容。没有就 404
    if (showPage) {
        showPage.style.display = 'block';
    } else {
        document.querySelector('.error').style.display = 'block';
    }
}) 

history 模式

History 对象包含用户(在浏览器窗口中)访问过的 URL。 History 对象是 window 对象的一部分,可通过 window.history 属性对其进行访问。它表示当前窗口的浏览历史。当页面发生改变时,只会改变页面的路径,不会刷新页面。 所以我们操作 History 对象 就相当于操作浏览器上对应的 url。

利用H5的 history中新增的两个API pushState() 和 replaceState() 和一个事件onpopstate监听URL变化

History 对象属性

属性说明
length返回历史列表中的网址数

History 对象方法

方法说明
back()history.back(); 加载 history 列表中的前一个 URL
forward()history.forward(); 加载 history 列表中的下一个 URL
go()history.go(); 加载 history 列表中的某个具体页面
pushState()该方法用于在历史中添加一条记录。pushState()方法不会触发页面刷新,只是导致 History 对象发生变化,地址栏会有变化。语法:history.pushState(object, title, url)
replaceState()该方法用来修改 History 对象的当前记录,用法与 pushState() 方法一样。

以上方法很少用,了解即可,具体用到再查一下文档。下面说到的就是核心了

popstate 事件

每当 history 对象出现变化时,就会触发 popstate 事件。

那什么时候触发?我罗列了一下:

触发时机说明
back()history.back(); 加载 history 列表中的前一个 URL
forward()history.forward(); 加载 history 列表中的下一个 URL
go()history.go(); 加载 history 列表中的某个具体页面

那 js 监听这个浏览器触发 popstate 事件做对应的操作。popstate事件指定回调函数,回调函数的参数是一个 event 事件对象,它的 state 属性指向当前的 state 对象。

模拟一下对应原理:

// 监听 popstate 变化,点击浏览器的前进后退会触发
window.addEventListener('popstate', function () {
    // e.state 相当于 history.state
	console.log(history.state);
    // 这里似 
}) 

history模式的问题

通过history api,我们丢掉了丑陋的 #,但是它也有个问题:不怕前进,不怕后退,就怕刷新,F5,(如果后端没有准备的话),因为刷新是实实在在地去请求服务器的,不玩虚的。 在hash模式下,前端路由修改的是#中的信息,而浏览器请求时是不带它玩的,所以没有问题。 但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,会分分钟刷出一个404来。

结语

目前我们用的 React 与 Vue 框架所用的路由都有这两种模式选择。

所以希望看完这篇文章对你有帮助,文中如有错误,欢迎在评论区指正,如果这篇文章帮助到了你,

🌹🌹🌹欢迎点赞和关注🌹🌹🌹,后续会输出更好的分享。

欢迎关注公众号:【程序员米粉】
公众号分享开发编程、职场晋升、大厂面试经验

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值