vue-router 的 hash 与 history 哪个模式会刷新页面?

598 阅读3分钟

写在前面

不知道大家有没有在 router 上犯过傻,最近被小伙伴难倒了一下,做个记录,是什么呢,她按往常一样通过 localhost:8080 打开了自己本机的项目,但是这次 “手贱”,自己不仅输入了ip地址,还输入了主页的路径 localhost:8080/overview,打开后发现并没有进到主页,然后一直在纠结为啥没有进入,而这个时候被强行拉进来的我,可能也是脑袋瓜不够清醒,一不小心就被带偏了,也是一直顺着她的方式,检查来检查去确实路径没啥问题,耽误了好几分钟才恍然发现,原来是路由哈希没写上的搞的鬼,终于真相大白,所以借此做下记录,也趁机温习一下 vue-router 原理吧。

前端路由原理

hash 模式

hash 模式是 vue router 的默认模式,如果平时不怎么关注 vue-router 的小伙伴可能都不会注意到,原来vue-router 默认的模式就是 hash

一般的 url 组成成分

url: juejin.cn:8080/creator?sta…

location.protocal => https

location.hostname => juejin.cn

location.host => juejin.cn:8080

location.port => 8080

location.pathname => /creator

location.search => ?status=all

location.hash => #/home

hash 特点分析

虽然 hash 模式只是 hash 变化,真正的路径并没有变化,但是 hash 依然能够触发网页跳转,也支持浏览器的前进和后退。如果平时观察仔细我们还会发现 hash 的页面跳转方式其实很特殊,hash 变化时,页面并不会刷新,只是内容进行了替换,而内容替换这种行为完全由前端控制,与 Server 端无关,因此这种模式使用这种模式的应用也被称为 SPA 应用

代码演示

实现 hash 主要利用 window 的 onhashchange 这个钩子函数,当监听到 url 中的 hash 变化时,调用 onhashchange 这个函数,完成相应的动作,下面通过一段简单的 hash 切换代码演示 hash 切换的监控, 这里设置了一个按钮,用于跳转到 Yimwu_Home 这个页面,通过这个跳转来验证 onhashchange 是否如我们所想的那样,能够成功监听到 hash 变化

<body>
  <h3>Old Hash: <span id="oldhash"></span></h3>
  <h3>Current Hash: <span id="newhash"></span></h3>
  <button id="btn">Goto Yimwu_Home</button>
  <script>
    const btn = document.getElementById('btn')
    // 给按钮绑定事件
    btn.addEventListener('click', () => {
      location.href = '/#/yimwu-home'
    })
    // hash 监听
    window.onhashchange = (hashevent) => {
      const oldhash = document.getElementById('oldhash')
      const newhash = document.getElementById('newhash')
      // 将新、旧路径赋值到页面对应位置
      oldhash.innerText = hashevent.oldURL
      newhash.innerText = hashevent.newURL
      console.log(hashevent)
    }
  </script>
</body>
复制代码

GIF 2022-6-7 22-12-30.gif

如上图所示,当通过按钮跳转到 yinwuhome 时,发生了 hash 变化,触发 onhashchange,因此old Hash 与 Currend Hash 被更新,当点击浏览器前进和后退时, onhashchange 同样也监听到了 hash 变化,再次对 old Hash 与 Currnent Hash 进行更新,通过上面简单的实验,应该大致就可以理解 hash 模式的设计方式了吧。

history 模式

history 模式特点分析

与 hash 相似的是 history 模式也不刷新页面,唯一和 hash 不同的是 history 所采用的路径规范不同,hash 采用的是路径末端的 hash 变化来切换路由,而 history 模式是通过模拟路径变化来切换路由。

代码演示

实现 history 主要使用的是 history.pushState 和 window 上的 onpopstate 钩子函数,下面依然通过一个简单的路由切换按钮来演示路由切换过程

<body>
  <h3>Current path: <span id="newpath"></span></h3>
  <button id="btn">Goto Yimwu_Home</button>
  <script>
    const btn = document.getElementById('btn')
    const newpath = document.getElementById('newpath')
    btn.addEventListener('click', () => {
      const state = {name: 'yimwu-home'}
      // 不会触发 onpopstate 钩子
      history.pushState(state, '', 'yimwu-home')
      // =============  路由切换逻辑 =============== //
      newpath.innerText = location.pathname
    })
    // 监听 path 变化,浏览器前进、后退触发
    window.onpopstate = (event) => {
      console.log(event)
      newpath.innerText = location.pathname
    } 
  </script>
</body>
复制代码

GIF 2022-6-7 22-47-57.gif

如上图所示,当通过按钮跳转到 yinwuhome 时,可以观察到 Path 的变化,但是此时并没有触发 onpopstate。onpopstate 只会在浏览器前进、后退时触发,因此,在 history 模式下,我们路由切换的逻辑需要写在 history.pushState 触发后,也就是说当执行 pushState 时,就是需要切换路由的时刻,那么此时前端就需要进行相应的页面渲染替换动作的执行。