vue-router的实现原理hash/history、导航守卫、导航解析流程

news2024/11/24 14:45:19

文章目录

    • 一、SPA与前端路由
    • 二、vue-router实现原理(模式)
      • hash模式
      • history模式
    • 三、vue-router中的route和router
    • 四、vue-router有哪几种导航守卫
      • 全局守卫
      • 路由独享的守卫
      • 路由组件内的守卫
    • vue-router完整的导航解析流程

一、SPA与前端路由

前端路由本质是,通过改变 URL,在不重新请求页面的情况下,更新页面视图。

传统的页面应用,是用一些超链接来实现页面切换和跳转的。而vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系。

  • SPA(单页面应用,全程为:Single-page Web applications)指的是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序,简单通俗点就是在一个项目中只有一个html页面,它在第一次加载页面时,将唯一完成的html页面按需加载的组件一起下载下来,所有的组件的展示与切换都在这唯一的页面中完成,这样切换页面时,不会重新加载整个页面,而是通过路由来实现不同组件之间的切换。

优点

  • 具有桌面应用的即时性、网站的可移植性和可访问性
  • 用户体验好、快,内容的改变不需要重新加载整个页面
  • 良好的前后端分离,分工更明确

缺点

  • 不利于搜索引擎的抓取
  • 首次渲染速度相对较慢

二、vue-router实现原理(模式)

更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2种方式:

  • hash – 默认值,利用 URL 中的hash(http://localhost:8080/#/login)
  • history – 利用URL中的路径(http://localhost:8080/login)

hash模式和history模式的区别

  • hash的url有’#'号,history没有
  • history和hash都是利用浏览器的两种特性实现前端路由,history是利用浏览历史记录栈的API实现,hash是监听location对象hash值变化事件来实现
  • history是H5新增,并且需要后端配合,如果后端不配合刷新新页面会出现404,hash不需要
  • HashRouter的原理:通过window.onhashchange方法获取新URL中hash值,再做进一步处理;HistoryRouter的原理:通过history.pushState 使用它做页面跳转不会触发页面刷新,使用window.onpopstate 监听浏览器的前进和后退,再做其他处理

设置路由模式

const router=new VueRouter({
    mode:'hash',
    routes:[...]
})

hash模式

vue-router默认hash模式,使用URL的hash来模拟一个完成URL,于是当URL改变时,页面不会重新加载

  • hash(#)是URL的锚点,代表的是页面中的某个位置,单单改的是#后的部分,浏览器只会滚动搭到相应的位置,不会重新加载页面,也就是说hash 出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面
  • 同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;
  • 所以说Hash模式通过锚点值的改变,根据不同的值,渲染 指定DOM位置 的不同数据。
  • hash 模式的原理是 onhashchange 事件(监测hash值变化),可以在 window 对象上监听这个事件。

通过下面的demo对hash操控路由并添加到历史记录有个更深刻的了解

有文件index.html、home.html、about.html,三个文件同目录
home.html、about.html随便放点东西,相当于vue里面两个子组件
index.html文件内容如下

<!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">
  <title>Document</title>
  <script src="../jquery.min.js"></script>
  <style>
    .active{
      color: red;
    }
  </style>
</head>
<body>
  <ul id="navagation">
    <li>
      <a href="#home.html">home</a>
    </li>
    <li>
      <a href="#about.html">about</a>
    </li>
    <li>
      <button id="btn">后退</button>
      <button id="btn2">前进</button>
    </li>
  </ul>
  <div id="content"></div>
<script>
  $(document).ready(function(){
    if(location.hash){
      var hashPage = location.hash.split('#')[1]
      $('#content').load(hashPage)
      $("#navagation a").removeClass('active')
      $("#navagation a").each(function(){
        if($(this).attr('href')===`#${hashPage}`){
          $(this).addClass('active')
        }
      })
    }
    document.getElementById('btn').onclick = function(){
      // window.history.go(-1)
      window.history.back()
    }
    document.getElementById('btn2').onclick = function(){
      window.history.forward()
    }
    window.onhashchange = function(e){
      console.log(history.length)
      // var hashPage = location.hash.split('#')[1]
      var hashPage = e.newURL.split('#')[1]
      $('#content').load(hashPage)
    }
  })
</script>
</body>
</html>

history模式

HTML5 history新增了两个API: history.pushState 和 history.replaceState

两个api都接受三个参数

  • 状态对象(state object):一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。
  • 标题(title):FireFox浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。
  • 地址(URL): 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

相同之处是两个API都会操作浏览器的历史记录,而不会引起页面的刷新。不同之处在于pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录

<!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">
  <title>Document</title>
  <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
  <style>
    .active{
      color: red;
    }
  </style>
</head>
<body>
  <ul id="navagation">
    <li>
      <button id="btn1">pushState</button>
      <button id="btn2">getLen</button>
      <button id="btn3">replaceState</button>
      <button id="btn4">前进</button>
      <button id="btn5">后退</button>
    </li>
  </ul>
  <div>栈:<span></span></div>
  <div id="content"></div>
  <script>
    $(document).ready(function(){
      let x = 1;
      $('span').html("当前历史记录栈总数:"+ history.length)
      let page = ''
      let y = 1;
      $('#btn1').click(function(){
        y = x
        // 压栈
        page = "test"+x+'.html'
        history.pushState({page:page},"",page)
        x++
        $('#content').load(page)
      })
      $("#btn2").click(function(){
        $('span').html("当前历史记录栈总数:"+ history.length)
      })
      $('#btn3').click(function(){
        if(y<=1) return
        y--
        // 替换
        history.replaceState({},"","test"+y+'.html')
        x = y+1
      })
      $('#btn4').click(function(){
        // 前进
        history.forward()
      })
      $('#btn5').click(function(){
        // 后退
        history.back()
      })
      window.addEventListener("popstate",(e)=>{
        console.log(e)
        if(!e.state) return
        $("#content").load(e.state.page)
      })
    })
  </script>
</body>
</html>

三、vue-router中的route和router

router 是VueRouter的实例,router是一个全局的路由对象,里面有很多的属性和方法,常见的就是this.$router.push()
在这里插入图片描述

route相当于正在跳转的路由对象,可以从route里面获取hash,name ,path,query,params等属性方法
在这里插入图片描述

四、vue-router有哪几种导航守卫

有三种:全局守卫,路由独享守卫,路由组件内的守卫
主要用来通过跳转或取消的方式守卫导航。
例如判断登录信息:没登录全部跳到登录页。判断必要操作是否进行没进行的话中断跳转。

全局守卫

  1. router.beforeEach 全局前置守卫 进入路由之前,必须调用next
    应用场景:导航前置守卫 在路由跳转之前进行判断和拦截,一般用来做一些进入页面的限制,比如未登录不能进入某些页面
    有三个参数
    • to: Route: 即将要进入的目标 路由对象
    • from: Route: 当前导航正要离开的路由
    • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
router.beforeEach((to, from,next) => {
	const user = sessonStorage.getItem('infromation')
    if(to.path=='/login'){
        next()
    }else if(user){
    	next()
    }else{
    	next('/login')
    }
})

  1. router.beforeResolve 全局解析守卫 在beforeRouteEnter调用之后调用,必须调用next
router.beforeResolve((to, from,next) => {
	next()
})
  1. router.afterEach 全局后置钩子 进入路由之后
    应用场景:跳转路由后组件默认在顶部
router.afterEach((to, from) => {
    document.title = to.title
    window.scrollTo(0,0)
})

为路由跳转加进度条
下载nprogress包 npm i nprogress
在main.js中引入

import NProgress from 'nprogress' // 导入进度条插件
import 'nprogress/nprogress.css' // 导入样式
// 默认关闭进度条
NProgress.configure({ showSpinner: false })

在全局导航守卫中添加

router.beforeEach((to, from, next) => {
  // 在准备跳转之前开启进度条
  NProgress.start()
  // 判断是否登录
  next()
})
// 后置守卫
router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})

路由独享的守卫

这个路由用的比较少,必须调用next

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
        next()
      }
    }
  ]
})

路由组件内的守卫

组件内的守卫有3种,beforeRouteEnter(第一次创建组件实例前)、beforeRouteUpdate(在组件被复用的时候调用)、beforeRouteLeave(离开组件)

beforeRouteEnter:如/path/:id这一个路由,第一次导航/path/id001会进入该组件内守卫,切换导航为/path/id002的时候不会触发该守卫方法
beforeRouteUpdate: 如/path/:id这一个路由,第一次导航/path/id001不会触发该守卫卫,切换导航为/path/id002的时候会触发该守卫方法
beforeRouteLeav:当离开该导航才会触发该守卫方法

beforeRouteEnter(to,from,next){
  console.log("beforeRouteEnter")
  next(vm=> {
     console.log(vm,'vm')
  })
},
beforeRouteUpdate(to,from,next){
  console.log("beforeRouteUpdate")
  next()
},
beforeRouteLeave(to,from,next){
  console.log("beforeRouteLeave")
  next()
}

vue-router完整的导航解析流程

1.导航被触发。
2.在失活的组件里调用离开守卫。
3.调用全局的 beforeEach 守卫。
4.在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
5.在路由配置里调用 beforeEnter
6.解析异步路由组件。
7.在被激活的组件里面调用 beforeRouterEnter
8.调用全局的 beforeResolve 守卫(2.5+)。
9.导航被确认。
10.调用全局的 afterEach钩子。
11.触发 DOM 更新。
12.用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

导航守卫执行顺序流程图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/624415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3年经验面试20K+测试岗,看到这样的面试题我懵了....

我要跳槽&#xff01;我是着急忙慌的准备简历——3年软件测试经验&#xff0c;可独立测试大型产品项目&#xff0c;熟悉项目测试流程...薪资要求&#xff1f;3年测试经验起码能要个20K吧 我加班肝了一页半简历&#xff0c;投出去一周&#xff0c;面试电话倒是不少&#xff0c;…

【Web服务应用】Tomcat部署与优化

Tomcat部署 一、Tomcat简介二、tomcat组件2.1核心组件2.2Tomcat功能组件2.3Tomcat 请求过程 三、部署Tomcat服务3.1Tomcat虚拟主机配置 四、Tomcat多实例部署五、tomcat优化5.1tomcat服务优化5.2JVM的优化5.3内核的优化 一、Tomcat简介 一款 java 开发的开源的 Web 应用服务程序…

8.面向对象编程(中级部分)|Java学习笔记

文章目录 IDEA介绍包注意事项和使用细节包的三大作用包的本质分析&#xff08;原理&#xff09; 访问修饰符面向对象编程三大特征封装封装的理解和好处封装的实现步骤&#xff08;三步&#xff09; 继承继承的深入讨论/细节问题继承的本质分析super关键字super 给编程带来的便利…

是德E3648A 双路输出电源技术参数

是德基础直流电源具备所需的各种基本特性&#xff0c;适用于预算紧张的用户。E3640系列30-100W GPIB单路和双路输出电源外形小巧&#xff0c;适合作为台式和系统电源使用。它的输出纹波和噪声较低&#xff0c;并内置测量和基本可编程功能。Keysight E3648A 90W多路输出电源是一…

和鲸社区数据分析每周挑战【第九十二期:学生成绩影响因素分析】

和鲸社区数据分析每周挑战【第九十二期&#xff1a;学生成绩影响因素分析】 文章目录 和鲸社区数据分析每周挑战【第九十二期&#xff1a;学生成绩影响因素分析】一、前言二、数据读取和初步探索三、数据预处理1、处理缺失值2、类别变量转换 四、学业表现可视化1、绘制数学成绩…

探究Vue源码:mustache模板引擎(1) 什么是模板引擎

之前在讲虚拟dom和diff算法时说过后续会讲模板引擎 啊 那这边 说到做到哈 对这个问题 有个比较官方的回答 模板引擎是将数据变为视图的最优雅的解决方案 比如 将左侧数据变为右侧视图 大家应该最先想到的就是 v-for 其实 v-for 就是一种模板引擎语法 从图中看出 模板引擎处理…

Linux文件理解和系统调用

本文已收录至《Linux知识与编程》专栏&#xff01; 作者&#xff1a;ARMCSKGT 演示环境&#xff1a;CentOS 7 文件理解和系统调用 前言正文文件概念文件描述符文件描述符概念文件管理关于 files_struct文件描述符的分配一切皆文件思想 C语言文件操作文件的打开与关闭文件读写 文…

IMX6ULL裸机篇之SPI原理图

一. IMX6ULL的 SPI 实验 I.MX6ULL 有4 个 SPI 接口&#xff0c;可以通过这 4 个 SPI 接口来连接一些 SPI 外设。 I.MX6U-ALPHA 使用 SPI3 接口 连接了一个六轴传感器 ICM-20608 &#xff0c;本章我们就来学习如何使用 I.MX6U 的 SPI 接口来驱动 ICM-20608…

【vue3】09-vue组件化额外知识补充(上)-生命周期-ref引用

组件化-额外知识补充&#xff08;上&#xff09; 生命周期认识生命周期生命周期函数的演练 refs引用 生命周期 认识生命周期 什么是生命周期呢? 生物学上&#xff0c;生物生命周期指得是一个生物体在生命开始到结束周而复始所历经的一系列变化过程;每个组件都可能会经历从创…

适应新时代的FTP已经出现?这种产品有何过人之处?

大家都知道&#xff0c;FTP是用于在网络上进行文件传输的一套标准协议&#xff0c;它作为互联网最经典的协议之一&#xff0c;至今已经存在了50年。而随着时代发展&#xff0c;越来越多的用户与企业开始觉得FTP不够满足大家的需求&#xff0c;出现的问题与漏洞越来越多&#xf…

好用工具第4期:全能播放器PotPlayer

好用工具第4期:全能播放器PotPlayer Global Potplayer 是一款 Windows 平台的全能播放器。支持几乎所有的视频格式&#xff0c;音频格式&#xff0c;以及在线播放全世界的电视直播。 其官网是&#xff1a; https://potplayer.daum.net/?langzh_CN 特点 支持强劲引擎加速支持3…

【微服务】SpringCloudAlibaba

一 微服务架构 1.1 微服务 微服务其实是一种架构风格&#xff0c;我们在开发一个应用的时候这个应用应该是由一组小型服务组成&#xff0c;每个小型服务都运行在自己的进程内&#xff1b;小服务之间通过HTTP的方式进行互联互通。 1.2 微服务架构的常见问题 一旦采用微服务系…

【论文阅读】(2013)Exact algorithms for the bin packing problem with fragile objects

文章目录 一、摘要二、介绍三、之前在这个问题上的工作四、易碎物品背包问题的求解4.1 ILP模型4.2 基于KP01的方法4.3 动态规划 五、二元分支方案5.1 分支方案1&#xff08;基于决策变量的分支&#xff09;5.2 分支方案2&#xff08;基于yj和xji的分支&#xff09;5.3 将L2嵌入…

精进嵌入式系统设计

当涉及到嵌入式系统设计时&#xff0c;以下是一些建议和关键点&#xff0c;可以帮助您进行有效的设计&#xff1a; 确定需求&#xff1a;明确系统设计的功能需求和性能指标。了解系统的预期用途、功能要求、资源限制和实时性需求等。 硬件选择&#xff1a;根据需求选择合适的硬…

Visio matlab 图像取消边框

visio 图像取消边框 1.菜单栏→文件→选项→自定义功能区→勾选“开发工具”→确定 2.菜单栏→开发工具→显示ShapeSheet→页→Print Properties→将“PageLeftMargin”、“PageRightMargin”、“PageTopMargin”和“PageBottomMargin”均修改为0 &#xff08;双击单元格来编辑…

报表生成器FastReport .Net用户指南:“Text“对象、文本编辑

FastReport .Net是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案&#xff0c;使用FastReport .NET可以创建独立于应用程序的.NET报表&#xff0c;同时FastReport .Net支持中文、英语等14种语言&#xff0c;可以让你的产品保证真正的国际性。 FastReport.NET官方版…

微软MFC程序运行的正确顺序

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来看一下微软MFC程序运行的正确顺序。这真的只是一个小众话题。但是对理解MFC很重要。 很多人写了一堆MFC程序&#xff0c;却不知道MFC程序是怎么运行顺序的。我们就来看一看这个问题。 我在之前的帖子中…

Java IO模型图解(BIO NIO AIO)

一、冯诺伊曼模型 如图&#xff1a; 图片来源&#xff1a;百度百科 输入设备向计算机输入数据&#xff0c;输出设备接收计算机输出的数据。 所有的计算机程序&#xff0c;也都可以抽象为从输入设备读取输入信息&#xff0c;通过运算器和控制器来执行存储在存储器里的程序&am…

热修复/热更新

热修复/热更新 一.Android热修复二.热修复框架三.类加载器0.BootClassLoader1.PathClassLoader2.DexClassLoader 四.实现思路五.代码1.FixManager2.App3.更加标准的代码 五.制作补丁包1.写段有bug的工具类&#xff0c;并写个点击按钮调用2.运行项目到模拟器上3.修复ToastUtils工…

node_modules插件代码修改,如何快速修改防止npm install安装覆盖代码

一、背景 有些组件不满足业务时咱们只能修改插件的源码&#xff1a; 直接在项目的node_modules下找到插件的源码直接修改&#xff1b; 优点&#xff1a;简单直接、快速见效&#xff1b;缺点&#xff1a;不能持久化&#xff0c;一旦重新npm install安装就失效&#xff1b;不方…