VueRouter路由模式解析

news2025/9/19 7:31:08

VueRouter路由模式解析

前端路由的实现方式主要有两种:hash模式和history模式。

hash模式

window.location对象中有一个hash字段,可以获取地址栏中#字符及后边的所有字符。

hash也称作锚点,本身是用来做页面定位的,可以使对应id的元素显示在可是区域内。

比如说下面这张动图,通过锚点直接跳转到footer

请添加图片描述

hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,不会对请求有影响。

下图可以看到虽然地址是http://localhost:3000/index.html#footer,但是network中的请求是http://localhost:3000/index.html
请添加图片描述

由于hash值变化不会导致浏览器向服务器发出请求,而且hash改变会触发hashchange事件,浏览器的进后退也能对其进行控制,所以在 html5history 出现前,开发者基本都是使用 hash 来实现前端路由的。

history模式

HTML5规范提供了history.pushStatehistory.replaceState来进行路由控制。通过这两个方法可以改变url且不向服务器发送请求。同时不会像hash有一个#,更加的美观。但是如果刷新页面,那么请求的资源就是当前地址栏中的地址了,对于SPA应用来说就需要进行配置将所有的路由重定向到根页面。

调用pushState跳转到相同的路由时仍可以成功且路由栈数量会加1。
这个可以重写pushState方法来进行过滤。

const stack = [];
const originPushState = window.history.pushState;
window.history.pushState = function() {
  if(stack[stack.length - 1] === arguments[2]) {
    return;
  }
  stack.push(arguments[2])
  originPushState.call(history, ...arguments);
}

history.replaceStatehistory.pushState 却不会触发 popstate 事件,不过可以手动创建一个PopStateEvent并触发该事件。

function createPopStateEvent(state, title) {
  return new PopStateEvent("popstate", {
    state: state,
    title: title
  });
}

window.history.pushState = function() {
  if(stack[stack.length - 1] === arguments[2]) {
    return;
  }
  stack.push(arguments[2])
  window.dispatchEvent(createPopStateEvent(...arguments));
  originPushState.call(history, ...arguments);
}

VueRouter中的路由模式

文章中介绍的vue-router源码版本为v3.4.9

hash模式

hash模式中,VueRouter主要还是以history.pushState为首选,在不支持history的浏览器中才会通过改变location.hash的值来实现路由切换。

在源码中的hash.js文件中的pushHash方法明确定义。

// src/history/hash.js
function pushHash (path) {
  if (supportsPushState) {
    pushState(getUrl(path))
  } else {
    window.location.hash = path
  }
}

同时在beforeCreate监听hashchange方法,防止用户直接在地址栏上修改url。通过点击跳转的方式VueRouter做了处理并不会触发该方法。

const eventType = supportsPushState ? 'popstate' : 'hashchange'
window.addEventListener(
  eventType,
  handleRoutingEvent
)

hash模式为什么首先考虑使用history.pushState呢?
因为通过history.pushState可以设置state值,VueRouter在每个路由跳转时带有唯一的key,可以用于在浏览器后退前进时恢复到之前的滚动的位置。
在源码中的pushState方法中可以看到,在跳转前保存当前路由的滚动条位置,同时为跳转路由添加一个新key标识新路由。

function pushState (url?: string, replace?: boolean) {
  saveScrollPosition()
  const history = window.history
  // safari存在问题,路由栈中只能保存100,超过100个异常捕获用location来替换路由对象
  try {
    if (replace) {
      const stateCopy = extend({}, history.state)
     stateCopy.key = getStateKey()
     history.replaceState(stateCopy, '', url)
   } else {
     history.pushState({ key: setStateKey(genStateKey()) }, '', url)
   }
 } catch (e) {
    window.location[replace ? 'replace' : 'assign'](url)
  }
}

history模式

在初始化history模式时,监听popstate,在路由变化时恢复滚动条位置。

// src/history/html5.js
this.transitionTo(location, (route) => {
  if (supportsScroll) {
    handleScroll(router, route, current, true)
  }
})
window.addEventListener('popstate', handleRoutingEvent)

前面提到history.pushStatehistory.replaceState两个方法不会触发popstate方法,因此在pushreplace方法中,在路由切换成功后手动执行hashScroll方法。

// src/history/html5.js
push(location: RawLocation, onComplete?: Function, onAbort?: Function) {
    const { current: fromRoute } = this
    this.transitionTo(
      location,
      (route) => {
        pushState(cleanPath(this.base + route.fullPath))
        handleScroll(this.router, route, fromRoute, false)
        onComplete && onComplete(route)
      },
      onAbort
    )
  }

abstract模式

VueRouter中除了hashhistory两种模式外,还新增了一个abstract模式,用来在不支持浏览器的环境中充当一个备用方案(例如Weex)。

abstract模式中新建了一个对象用来模拟浏览器中路由栈。

this.stack = []

同时提供了三个路由跳转方法pushreplacego,这三种方法跟hashhistory模式中的pushreplacego方法类似,来看看是怎么实现的。

// src/history/abstract.js push()方法
route => {
  // 在路由栈中添加一个新路由
  this.stack = this.stack.slice(0, this.index + 1).concat(route)
  this.index++
  onComplete && onComplete(route)
}

因为非浏览器环境中没有前进后退按钮,因此replace其实就是替换掉路由栈中的最后一个路由。

// src/history/abstract.js replace()方法
route => {
  // 在路由栈中替换掉最后一个路由
  this.stack = this.stack.slice(0, this.index).concat(route)
  this.index++
  onComplete && onComplete(route)
}

go方法中同样对传入的数字进行判断是否在路由栈的范围内,否则不执行。

// src/history/abstract.js go()方法
const targetIndex = this.index + n
if (targetIndex < 0 || targetIndex >= this.stack.length) {
  return
}

之后直接将路由索引指向需要跳转的路由索引同时更新当前路由。

// src/history/abstract.js go()方法
const route = this.stack[targetIndex]
this.confirmTransition(
  route,
  () => {
  this.index = targetIndex
  this.updateRoute(route)
  // ...
)

// src/history/base.js
updateRoute(route: Route) {
  this.current = route
  this.cb && this.cb(route)
}

无论是hash还是history模式都需要对浏览器当前的URL产生影响,通过与abstract结合也可以实现在已存在的路由页面中内嵌其他的路由页面,而保持在浏览器当中依旧显示当前页面的路由path

比如定义了一个hash模式并存在两个路由的实例挂载在app上,其中第二个路由中又定义一个abstract模式的路由。这时候切换/route1/route2并不会影响URL


const routes = [
  {
    path: '/',
    component: { template: `<div>default view</div>` }
  },
  {
    path: '/abstractRoute',
    component: {
      name: "abstract",
      template: '<div><h1 @click="toRoute(1)">跳转到router1</h1><h1 @click="toRoute(2)">跳转到router2</h1><router-view></router-view></div>',
      methods: {
        toRoute(num) {
          this.$router.push(`/route${num}`);
        }
      },
      router: new VueRouter({
        routes: [
          {
            path: '/route1',
            component: {template:'<h1>abstract route 1</h1>'}
          },
          {
            path: '/route2',
            component: { template:'<h1>abstract route 2</h1>'}
          },
        ],
        mode: 'abstract'
      })
    }
  },
]

const app = new Vue({
  router: new VueRouter({
    routes,
    mode: 'hash'
  }),
  template: `<div><router-link to="/">to /</router-link>
    <router-link to="/abstractRoute">to abstractRoute</router-link>
    <router-view></router-view>
    </div>`,
}).$mount('#app')

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

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

相关文章

BGP联邦实验

实验目的&#xff1a; 实验拓扑&#xff1a; IP地址规划&#xff1a; AS2内部&#xff1a; 172.16.0.0/16 172.16.0.0/24---P2P网络 172.16.1.0/24----MA网络 172.16.1.0/29 172.16.1.8/29 172.16.1.16/29 172.16.1.24/29 172.16.1.32/29 172.16.1.40/29 172.16.2.0/24--…

Golang每日一练(leetDay0032) 二叉树专题(1)

目录 94. 二叉树的中序遍历 Binary Tree Inorder Traversal &#x1f31f; 95. 不同的二叉搜索树 II Unique Binary Search Trees II &#x1f31f;&#x1f31f; 96. 不同的二叉搜索树 Unique Binary Search Trees &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷…

基于 FPGA+DSP 的冲击波超压测试系统设计与实现-系统测试(二)

5 系统功能测试及仿真 在完成系统硬件电路板的设计和软件程序的开发后&#xff0c;本章分别对 A/D 采集模块、 DDR3 SDRAM 存储模块的读写波形进行了测试&#xff0c;并对千兆网卡传输模块通过 Wireshark 软件进行抓包测速&#xff0c;调试成功并确认无误后将各模块组装起来对系…

Unity之ASE实现根据ScreenPosition改变渲染效果

前言 我们知道ScreenPosition节点,代表了屏幕空间的坐标,那么它有哪些用处呢?今天我们就来给大家演示一个效果,如下图所示:我们拉远拉进摄像机的位置,任务的渲染会根据不同距离有一定变化。 ScreenPosition介绍 Screen Position 节点输出当前像素的屏幕位置。根据所选…

7nm+跨域计算+极致性价比,这家芯片厂商助攻车企「降本增效」

汽车芯片赛道的「卷」&#xff0c;或许超出了所有人的预期。对于单纯TOPS算力的比拼&#xff0c;已经翻篇&#xff0c;如何让车企有的用&#xff0c;用得上&#xff0c;还要用得好&#xff0c;已经是新风向。 实际上&#xff0c;在汽车智能化刚刚开始的2018年&#xff0c;彼时类…

2.4 随机变量函数的分布

学习目标&#xff1a; 学习随机变量函数的分布&#xff0c;我会采取以下步骤&#xff1a; 熟悉随机变量的基本概念和分布&#xff1a;在学习随机变量函数的分布之前&#xff0c;需要先掌握随机变量的基本概念和分布&#xff0c;包括离散型随机变量和连续性随机变量的概率密度…

《Java8实战》第4章 引入流

集合是 Java 中使用最多的 API。 4.1 流是什么 流是 Java API 的新成员&#xff0c;它允许你以声明性方式处理数据集合&#xff08;通过查询语句来表达&#xff0c;而不是临时编写一个实现&#xff09;。可以看作是遍历数据集的高级迭代器&#xff0c;而且还可以并行的处理。…

语音识别实战(python代码)(一)

语音识别实战 &#xff08;python &#xff1a;pyttsx、SAPI、SpeechLib实例代码&#xff09;(一&#xff09; 本文目录&#xff1a; 一、语音识别的基本原理 &#xff08;1&#xff09;、语音识别的起源与发展 &#xff08;2&#xff09;、语音识别的基本原理 &#xff0…

吸烟行为检测系统(Python+YOLOv5深度学习模型+清新界面)

摘要&#xff1a;吸烟行为检测软件用于日常场景下吸烟行为监测&#xff0c;快速准确识别和定位吸烟位置、记录并显示检测结果&#xff0c;辅助公共场所吸烟安全报警等。本文详细介绍吸烟行为检测系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数…

BGA封装与PCB差分互连结构的设计与优化

摘要&#xff1a;随着电子系统通信速率的不断提升&#xff0c;BGA封装与PCB互连区域的信号完整性问题越来越突出。 针对高速BGA封装与PCB差分互连结构进行设计与优化&#xff0c;着重分析封装与PCB互连区域差分布线方式&#xff0c;信号布局方式&#xff0c;信号孔/地孔比&…

Unity编写Shader内置各种矩阵和方法介绍

返回目录 大家好&#xff0c;我是阿赵。 这里记录一下Unity编写Shader内置各种矩阵和方法 一、Unity内置转换矩阵 1、MVP类矩阵 UNITY_MATRIX_MVP:Current model * view * projection matrix. UNITY_MATRIX_MV:Current model * view matrix. UNITY_MATRIX_V:Current view m…

静态库与动态库

库是已经写好的、成熟的、可复用的代码。在我们的开发的应用中经常有一些公共代码是需要反复使用的&#xff0c;就把这些代码编译为库文件。库可以简单看成一组目标文件的集合&#xff0c;将这些目标文件经过压缩打包之后形成的一个可执行代码的二进制文件。库有两种&#xff1…

uniapp页面后退时更改页面内容【uniapp如何区分页面是跳转来的还是后退来的】【伸手党福利】

目录应用场景实现目标分析技术难点解决方法另附&#xff1a;自动登录判断跳转页面ps2 这个案例的实际简单的解决方法应用场景 建立一个自动登录的中间页&#xff0c;如果自动登录&#xff0c;则自动跳转到内部应用。如果自动登录失败&#xff0c;则显示用户名密码输入页。 发现…

文心一言对于宣传文案理解

前言 前段时间对于文心一言开放部分内测邀请&#xff0c;有幸获得邀请内测权限&#xff01;抱着试一试的态度对其进行了使用&#xff0c;结果还是比较满意的。我们来看一下我所说的满意是否能够达到你的要求&#xff01;&#xff01;&#xff01; 使用逻辑 文心一言的使用还…

静态路由的原理和配置(理论详细实验全面)

第五章&#xff1a;静态路由 目录 第五章&#xff1a;静态路由 5.1路由器的工作原理 5.1.1路由器根据路由表转发数据 5.1.2 路由信息获取的方式 5.2路由选路原则 5.2.1最长匹配原则 5.2.2路由优先级 5.2.3路由度量值 5.3静态路由 5.3.1静态路由实验 5.3.2缺省路由实…

多模态模型技术综述

多模态架构导语1. Image2Text1.1 图像数据集准备1.2 图像to文本的生成模型1.2.1 M2 模型&#xff08;Meshed—Memory Transformer&#xff09;Memory-Augmented EncoderMeshed Decoder2. text2Image2.1 生成对抗网络&#xff08;GAN&#xff09;2.1.1 文本生成图像基础GAN2.1.2…

4.1 不定积分的概念与性质

思维导图&#xff1a; 学习目标&#xff1a; 学习不定积分&#xff0c;我会采取以下几个步骤&#xff1a; 1.学习基本的积分表&#xff1a;首先&#xff0c;我会学习基本的积分公式&#xff0c;例如幂函数、指数函数、三角函数、反三角函数等的积分公式。这些公式是不定积分…

enote笔记法之附录1——“语法词”(即“关联词”)(ver0.22)

章节&#xff1a;enote笔记法之附录1——“语法词”&#xff08;即“关联词”&#xff09;&#xff08;ver0.22&#xff09; 上面的是截屏的完整版&#xff0c;分割线下面的是纯文字版本&#xff1a; 作者姓名&#xff08;本人的真实姓名&#xff09;&#xff1a;胡佳吉 居…

计及需求侧响应日前、日内两阶段鲁棒备用优化(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

机器学习实战:Python基于K近邻KNN进行分类预测(四)

文章目录1 前言1.1 K近邻的介绍1.2 K近邻的应用2 二维数据集演示2.1 导入函数2.2 导入数据2.3 训练模型及可视化3 莺尾花数据集全数据演示3.1 导入函数3.2 导入数据3.3 训练模型及预测4 模拟数据集演示4.1 导入函数4.2 模拟数据集4.3 建模比较5 马绞痛数据pipeline演示5.1 下载…