web前端面试--路由中history与hash的区别(附带源码)

本文深入探讨了前端路由中hash和history两种模式的特点、监听方式以及URL的变更方法。hash模式适用于旧版浏览器,不发起请求但能监听hashchange事件;history模式提供更好的用户体验,但需要后台配置以避免刷新后的404错误。文章还展示了源码示例,解释了如何监听和改变这两种模式的URL。
摘要由CSDN通过智能技术生成

web面试题

本人是一个web前端开发工程师,主要是vue框架,整理了一些面试题,今后也会一直更新,有好题目的同学欢迎评论区分享 ;-)

web面试题专栏:点击此处

在这里插入图片描述



前言

history和hash都是利用浏览器的两种特性实现前端路由
以下代码示例用原生HTML,不用vue框架实现。


一、特点

hash的特点

  • url后面写#锚点,由于 hash 值变化不会导致浏览器向服务器发出请求,而且hash 改变会触发 hashchange 事件(hashchange只能改变 # 后面的url片段)。
  • 因为hash发生变化的url都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了,所以人们在html5 的 history 出现前,基本都是使用 hash 来实现前端路由的。
  • hash本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。

history的特点

  • hash 能兼容到IE8, history 只能兼容到 IE10,histroy兼容性不好。
  • 如果后台没有配置,刷新可能导致404。(后面源码可重现)
  • hash 的传参是基于 url 的,如果要传递复杂的数据,会有体积的限制,而history模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。

二、监听

单纯打印 location 信息,不做业务处理,演示用~

hash的监听方式

// 监听hash模式
window.addEventListener("hashchange", (e) => {
  console.log("hash:", location.hash);
});

histroy的监听方式

// 监听history模式
// 只能监听history.go、histroy.back()、history.forward()
window.addEventListener('popstate', (e) => {
  console.log('onpopstate:', e, location.pathname)
})
// history.replaceState(),以及history.pushState() 需要重写
let rawReplace = history.replaceState
history.replaceState = (...arg) => {
  rawReplace.apply(history, arg)
  console.log('replaceState change...')
}

let rawPush = history.pushState
history.pushState = (...arg) => {
  rawPush.apply(history, arg)
  console.log('pushState change...')
}

三、改变url的方式

通过手动或者JS的方法修改url,已达到触发监听事件。

hash改变url的方式

  1. 通过浏览器输入栏手动输入网址来达到修改;
  2. 通过浏览器的前进后退方式;
  3. JS的方式location.href=“#/xxx”。

histroy改变url的方式

  1. 通过浏览器的前进后退方式;
  2. JS的方式 history.pushState() 切换路由前的url会保存在history中;
  3. JS的方式 history.replaceState() 切换路由前的url不会保存在history中;
  4. JS的方式 go()方法可以在用户的历史记录中任意跳转。这个方法接收一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(类似于后退按钮),正数表示向前跳转(类似于前进按钮)history.go(0)等于刷新
  5. JS的方式 back()方法用于模仿浏览器的后退按钮,相当于history.go(-1);
  6. JS的方式 forward()方法用于模仿浏览器的前进按钮,相当于history.go(1)。

四、源码

hash的源码

<!--
 * @Author: Penk
 * @LastEditors: Penk
 * @LastEditTime: 2023-10-13 10:09:15
 * @FilePath: \web-interview-questions\路由\hash路由.html
 * @email: 492934056@qq.com
-->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
  <title>Document</title>
  <style>
    .codeBox {
      background-color: black;
      padding: 10px;
      color: white;
    }
  </style>
</head>

<body style="margin-top: 50px; margin-left: 50px">
  <main>
    <button id="hashBtn">随机hash路由</button>
    <br />
    <span style="color: red; font-size: 12px">打开控制台可以看数据</span>

    <p>hash的监听:</p>
    <div class="codeBox">
      <code>
          window.addEventListener("hashchange", (e) => {
          <br />
          &nbsp;&nbsp; console.log("hash:", location.hash);
          <br />
          });
        </code>
    </div>

    <p>hash的变化方式:</p>
    <ul>
      <li>通过浏览器输入栏手动输入网址来达到修改</li>
      <li>通过浏览器的前进后退方式</li>
      <li>JS的方式location.href="#/xxx"</li>
    </ul>

    <p>特点:</p>
    <ul>
      <li>
        url后面写#锚点,由于 hash 值变化不会导致浏览器向服务器发出请求,而且
        hash 改变会触发 hashchange 事件(hashchange只能改变 #
        后面的url片段)。
      </li>
      <li>
        因为hash发生变化的url都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了,所以人们在
        html5 的 history 出现前,基本都是使用 hash 来实现前端路由的。
      </li>
    </ul>
  </main>

  <script>
    // 监听hash模式
    window.addEventListener("hashchange", (e) => {
      console.log("hash:", location.hash);
    });

    //  点击
    $("#hashBtn").click((e) => {
      location.href = "#/user" + Math.floor(Math.random() * 100);
    });
  </script>
</body>

</html>

在这里插入图片描述


history的源码

<!--
 * @Author: Penk
 * @LastEditors: Penk
 * @LastEditTime: 2023-10-13 10:31:10
 * @FilePath: \web-interview-questions\路由\history路由.html
 * @email: 492934056@qq.com
-->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
  <title>Document</title>
  <style>
    button+button {
      margin-left: 20px;
    }

    .codeBox {
      background-color: black;
      padding: 10px;
      color: white;
    }
  </style>
</head>

<body style="margin-top: 50px; margin-left: 50px">
  <main>
    <button id="pushStateBtn">pushState跳转,监听不了</button>
    <button id="replaceStateBtn">replaceState跳转,监听不了</button>
    <button id="goBtn">go(0)跳转,如果没有配置会返回404</button>
    <button id="backBtn">back跳转,popstate监听到了</button>
    <button id="forwardBtn">forward跳转,popstate监听到了</button>
    <button id="gotoHome">跳转到首页,测试用</button>

    <br />
    <span style="color: red; font-size: 12px">打开控制台可以看数据</span>

    <p>history的监听:</p>
    <div class="codeBox">
      <code>
          window.addEventListener("popstate", (e) => {
          <br />
          &nbsp;&nbsp; console.log("onpopstate:", e, location.pathname);
          <br />
          });
          <br />
          // history.replaceState(),以及history.pushState() 需要重写
          <br />
          let rawReplace = history.replaceState;
          <br />
          history.replaceState = (...arg) => {
          <br />
          &nbsp;&nbsp; rawReplace.apply(history, arg);
          <br />
          &nbsp;&nbsp; console.log("replaceState change...");
          <br />
          }
          <br />
          <br />

          let rawPush = history.pushState;
          <br />
          history.pushState = (...arg) => {
          <br />
          &nbsp;&nbsp; rawPush.apply(history, arg);
          <br />
          &nbsp;&nbsp; console.log("pushState change...");
          <br />
          }
          <br />
        </code>
    </div>

    <p>history的变化方式:</p>
    <ul>
      <li>通过浏览器的前进后退方式</li>
      <li>JS的方式 history.pushState() 切换路由前的url会保存在history中,并不会出发popstate</li>
      <li>
        JS的方式 history.replaceState() 切换路由前的url不会保存在history中,并不会出发popstate
      </li>
      <li>
        JS的方式 go()方法可以在用户的历史记录中任意跳转。
        这个方法接收一个参数,表示向后或向前跳转的页面数的一个整数值。
        负数表示向后跳转(类似于后退按钮),正数表示向前跳转(类似于前进按钮)。 history.go(0)等于刷新
      </li>
      <li>JS的方式 back()方法用于模仿浏览器的后退按钮,相当于history.go(-1),可以出发popstate</li>
      <li>
        JS的方式 forward()方法用于模仿浏览器的前进按钮,相当于history.go(1),可以出发popstate
      </li>
    </ul>

    <p>特点:</p>
    <ul>
      <li>hash 能兼容到IE8, history 只能兼容到 IE10。</li>
      <li>hash 本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。</li>
      <li>如果后台没有配置,刷新可能导致404。</li>
      <li>
        hash 的传参是基于 url 的,如果要传递复杂的数据,会有体积的限制,而 history
        模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。
      </li>
    </ul>
  </main>

  <script>
    // 监听history模式
    // 只能监听history.go、histroy.back()、history.forward()
    window.addEventListener('popstate', (e) => {
      console.log('onpopstate:', e, location.pathname)
    })
    // history.replaceState(),以及history.pushState() 需要重写
    let rawReplace = history.replaceState
    history.replaceState = (...arg) => {
      rawReplace.apply(history, arg)
      console.log('replaceState change...')
    }

    let rawPush = history.pushState
    history.pushState = (...arg) => {
      rawPush.apply(history, arg)
      console.log('pushState change...')
    }

    $('#pushStateBtn').click((e) => {
      let name = 'user' + Math.floor(Math.random() * 100)
      const state = {
        name
      }
      history.pushState(state, '', name)
      console.log('执行pushState,并不能触发popstate事件,只有浏览器前进后退才可以。')
    })

    $('#replaceStateBtn').click((e) => {
      history.replaceState(
        {
          name: 'user' + Math.floor(Math.random() * 100)
        },
        null,
        'user' + Math.floor(Math.random() * 100)
      )
      console.log('执行replaceState,并不能触发popstate事件,只有浏览器前进后退才可以。')
    })

    $('#goBtn').click((e) => {
      history.go(0)
    })

    $('#backBtn').click((e) => {
      history.back()
    })

    $('#forwardBtn').click((e) => {
      history.forward()
    })

    let href = window.location.href
    $('#gotoHome').click((e) => {
      location.href = href
    })
  </script>
</body>

</html>

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Penk是个码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值