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

news/2024/7/10 2:03:03 标签: vue.js, 前端, vue

文章目录

    • 一、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页面按需加载的组件一起下载下来,所有的组件的展示与切换都在这唯一的页面中完成,这样切换页面时,不会重新加载整个页面,而是通过路由来实现不同组件之间的切换。

优点

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

缺点

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

vuerouter_16">二、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>

vuerouterrouterouter_188">三、vue-router中的route和router

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

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

vuerouter_194">四、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()
}

vuerouter_299">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.niftyadmin.cn/n/412270.html

相关文章

教你如何多人播报配音把

你们有没有在日常生活中遇到短视频的配音呢&#xff1f;那你们知不知道多人播报配音呢&#xff1f;其实它就是指通过合成多个不同的声音&#xff0c;实现多人对话或演唱的效果&#xff0c;并且可选择不同的声音和语速进行播报。而且它可以应用在广告宣传、盲人听书、电影动画、…

【springCloud-2】Ribbon负载均衡

负载均衡&#xff0c;一般分为服务端负载均衡和客户端负载均衡。 服务端&#xff1a;如Nginx&#xff0c;F5等&#xff0c;请求到达服务器后进行负载均衡。 客户端&#xff1a;客户端获取到服务端的列表&#xff0c;自己经过一定的计算后选择某一台访问。 ribbon实现的就是客…

2023年学自动化测试?Python 还是 Java?“我“上车了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 自动化测试&#…

Proteus仿真之LCD1602

1.项目简介&#xff1a;利用Proteus仿真在LCD1602上显示字母。 2.设计思路&#xff1a;首先要读懂LCD1602的时序图和每一个端口高低电平时的含义。 然后&#xff0c;通过操作的端口的高低电平来达到操作数据的目的。主要思路是&#xff0c;根据端口的组合来&#xff0c;将数据…

实战干货——教你用Fiddler捕获HTTPS请求

目录 安装Fiddler 配置Fiddler 配置手机 iOS机安装证书 安全思考&#xff1f; 总结&#xff1a; 安装Fiddler 这里不特别说明了&#xff0c;网上搜索一大把&#xff0c;根据安装引导一步步安装即可。&#xff08;这里采用的是fiddler v4.6&#xff09; fiddler抓包视频教…

NetSuite 中国财务常用报表功能包

目录 1.致谢 2.功能说明 2.1 概述 2.2 报表说明 3.安装 4.操作指南 4.1 CLR_资产负债表 4.2 CLR_资产负债表&#xff08;期初/发生/结余&#xff09; 4.3 CLR_利润表 4.4 CLR_利润表季报 4.5 CLR_现金流量表 4.6 CLR_现金流量表季报 4.7 CLR_总账 4.8 CLR_序时账…

基于国产RK3588+多路H.265视频编解码 转码 3U VPX 方案

一、概述 3U VPX音视频转码模块是信迈科技推出的基于RK3588平台用于音视频的编解码、转码&#xff0c;本模块SDI视频、模拟音频输入&#xff0c;视频进行分辨率和帧率的变换&#xff0c;音频进行采样率和码率等的变换&#xff0c;网口输入的视频流进行解码或者转码&…

Oracle中改变表的Owner和tablespace

初用Oracle&#xff0c;很多的不熟悉&#xff0c;建完库&#xff0c;没有建用户&#xff0c;也没创建表空间&#xff0c;就直接system用户建表添加数据&#xff0c;几个月过去&#xff0c;表建了近百个&#xff0c;数据添加了几万条&#xff0c;才越来越觉得这种方式缺点太多&a…