持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
写在前面
不知道大家有没有在 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>
如上图所示,当通过按钮跳转到 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>
如上图所示,当通过按钮跳转到 yinwuhome 时,可以观察到 Path 的变化,但是此时并没有触发 onpopstate。onpopstate 只会在浏览器前进、后退时触发,因此,在 history 模式下,我们路由切换的逻辑需要写在 history.pushState 触发后,也就是说当执行 pushState 时,就是需要切换路由的时刻,那么此时前端就需要进行相应的页面渲染替换动作的执行。
vue-router 的 hash 与 history 哪个模式会刷新页面?
看完了文章的分析,最后 Callback 回答一下题目吧,答案是两个都不会刷新页面。 我们都知道面试官是出了名的喜欢挖坑的一个群体,这种典型的选择题就非常具有诱骗性,你回答哪个都是错误的,都是他就是不纠正你,继续让你分析和佐证,错上加错,接下来就是经典的 “回去等通知系列。。。。。。。。。”,所以在这种看似简单的问题上,我们还是需要多加巩固,排除隐患,毕竟有些坑,一跳进去,爬起来就已经没有机会从来了!
总结
vue-router 作为 Vue 全家桶中非常重要的组成成分,那么虽然使用起来非常简单,简单到如果不是项目负责人,可能都不需要动手去配置相关的路由,但是当我们需要真正自己动手去完成路由相关操作的时候,那么相比于直接傻瓜式按照文档去执行操作,我想如果能够从底层原理的角度来切入学习,了解原理,也许会让我们对它的理解更加深刻,也能够在理解原理的基础上来判断我们到底需要选择什么模式来支撑我们的项目开发!
往期好文推荐
面试官:说说从输入 URL 到页面显示到底经历了什么,体现一下你的知识广度
面试官:HTTPS 采用的是对称加密还是非对称加密?具体说说其加密过程
面试官:你就只会 npm run build 吗?(Webpack 配置 Vue+Ts)
面试官:连VuePress都没搭过还说开发过组件库?(VuePress 搭建)
面试官: 连 Vue 视图更新都不会写?(Vue视图更新原理【一】)
面试官: 能不能手写 Vue 响应式?(Vue2 响应式原理【完整版】)
面试官:能不能手写 Vue3 响应式(Vue3 原理解析之响应系统的实现)
面试官:说一下这个Loading动画实现思路 (CSS3 实现 Loading 动画)
面试官:你确定你说的防抖不是节流吗?( 面试题梳理系列 (二))
面试官:除了 HTTP,你还用过什么通信协议?(Websocket 在数字孪生中的应用)
面试官:你真的理解 Event Loop 吗?( JS 事件循环 )
面试官:v-for 中 key 为什么不能用 index,从原理层面聊聊?
面试官:vue-router 的 hash 与 history 哪个模式会刷新页面?
面试官:说说你平时用过的自适应方案(数字孪生可视化自适应方案)
写在最后
博主接下来将持续更新好文,欢迎关注博主哟!!
如果文章对您有帮助麻烦亲点赞、收藏 + 关注和博主一起成长哟!!❤️❤️❤️