Vue-Router 介绍及路由原理分析
文章目录
- Vue-Router 路由模式
- 单页面与传统页面跳转的区别
- Hash 模式
- History 模式
- abstract 模式
- 原理解析
- Hash 模式原理
- History 模式原理
- 路由使用
- 引入 Vue-Router
- 获取全局路由跳转参数的变化
- 获取路由中带的参数
- 重定向页面
Vue-Router 路由模式
单页面与传统页面跳转的区别
- 单页面
Vue 的单页面开发模式是基于组件和路由的配合,所有的页面均可视为组件,路由控制着访问路径,而每个路径映射一个组件。在单页模式中使用 a 标签做路由跳转是行不通的,因为本质上单页模式就只有一个 index.html 页面,所有的页面组件都在打包好的 JS 文件中,所以要使用 Vue-Router 的路由组件来跳转,这里的原因在后文中会有具体的例子解析。
- 传统页面
传统页面的开发模式,路由一般是由超链接(a 标签)来控制页面的跳转与切换,每次都会刷新整个页面,体验上不如单页模式。
Vue-Router 为我们提供了三种路由模式:
- Hash 模式
- History 模式
- abstract 模式
Hash 模式
Hash 模式是 Vue-Router 的默认模式,具体的体现是在浏览器地址栏上 URL 路径永远带着一个「#」号。在浏览器支持度上面,Hash 模式是比较强势的,甚至能兼容低版本的 IE 浏览器。「#」号后面内容的改变,不会引起页面对服务端的请求,所以也就不会重新加载页面。在部署服务器方面,个人认为 Hash 模式比 History 模式来得更为方便,因为 History 有 URL 重定向问题,需要在服务端去配置 url 重定向,否则会报 404 错误。市面上也有不少大厂是使用 Hash 模式进行开发的,比如网易云音乐:

History 模式
HTML5 History API 提供了一个 history.pushState 和 history.reolaceState 方法(浏览器支持情况不是很乐观),它能让开发人员在不刷新网页的情况下改变站点的 URL。因为 Hash 模式会带上一个「#」号,会让 URL 地址变得比较难看,所以很多开发者都会选择 History 模式开发。但有个缺点,前端的 URL 必须和实际向服务端发起的请求的 URL 保持一致,如果服务端没有对相应的路由做处理,则会返回 404 错误页面。
abstract 模式
abstract 模式针对的是没有浏览器环境的情况,比如 Weex 客户端开发,内部是没有浏览器 API 的,那么 Vue-Router 自身会对环境做校验,强制切换到 abstract 模式,如果默认在 Vue-Router 的配置项中不写 mode 的值,在浏览器环境下会默认启用 Hash 模式,在移动客户端下使用 abstract 模式。
原理解析
Hash 模式原理
大家常常会在浏览器上看到这样一种场景,点击某个文字,网页会跳转到某一个固定的位置,并且页面不会刷新。这便是浏览器的 a 标签锚点。Hash 模式被运用在了单页面开发的路由模式上,下面我们来简单实现一个通过 Hash 去控制页面组件的展示。 浏览器原生方法为我们提供了一个监听事件 hashchange,它能监听到的改变如下:
- 点击 a 标签改变 URL 地址;
- 浏览器的前进后退行为;
- 通过
window.location方法改变地址栏。
以上三种情况都会触发 hashchange 监听事件,通过这个事件我们可以获取到 localtion.hash,继而去匹配相应的组件,下面是简易代码实现:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Hash 模式</title></head><body><div><ul><li><a href="#/page1">page1</a></li><li><a href="#/page2">page2</a></li></ul><div id="route-view"></div></div><script type="text/javascript">// 下面为hash的路由实现方式// 第一次加载的时候,不会执行hashchange监听事件,默认执行一次window.addEventListener('DOMContentLoaded', Load);window.addEventListener('hashchange', HashChange);var routeView = null;function Load() {routeView = document.getElementById('route-view');HashChange();}function HashChange() {console.log('location.hash', location.hash);switch (location.hash) {case '#/page1':routeView.innerHTML = 'page1';return;case '#/page2':routeView.innerHTML = 'page2';return;default:routeView.innerHTML = 'page1';return;}}</script></body>
</html>
当初始的 HTML 文档被完全加载和解析完成之后, DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。 hashchange 不会被默认触发,所以网页首次加载完成后,需要默认执行一次 hashchange 监听方法要执行的函数 HashChange,当我点击代码中的两个 a 标签时,URL 地址栏改变触发 hashchange 事件, HashChange 方法通过拿到 location.hash 去匹配相应的组件(这里假设 page1、page2 为页面容器组件)。
在浏览器中打开HTML查看效果:

这样我们就实现了一个简易版的 Hash 路由模式,大家可以自己手动实现一下,加深记忆。
History 模式原理
下面来介绍 History 模式。
通过 History 模式去控制路由,会遇到一些麻烦,根本原因是 History 模式利用的时候 popstate 监听事件无法监听到 pushState、 replaceState、a 标签这三种形式的变化,浏览器的前进后退是可以监听到。那么有什么好的解决方案吗?
小知识:pushState 和 replaceState 都是 HTML5 的新 API,他们的作用很大,可以做到改变浏览器地址却不刷新页面。
我们可以通过遍历页面上的所有 a 标签,阻止 a 标签的默认事件的同时,加上点击事件的回调函数,在回调函数内获取 a 标签的 href 属性值,再通过 pushState 去改变浏览器的 location.pathname 属性值。然后手动执行 popstate 事件的回调函数,去匹配相应的路由。逻辑上可能有些饶,我们用代码来解释一下:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>History 模式</title></head><body><div><ul><li><a href="/page1">page1</a></li><li><a href="/page2">page2</a></li></ul><div id="route-view"></div></div><script type="text/javascript">// 下面为history的路由实现方式window.addEventListener('DOMContentLoaded', Load);window.addEventListener('popstate', PopChange);var routeView = null;function Load() {routeView = document.getElementById('route-view');PopChange();// 获取所有带 href 属性的 a 标签节点var aList = document.querySelectorAll('a[href]');// 遍历 a 标签节点数组,阻止默认事件,添加点击事件回调函数aList.forEach((aNode) =>aNode.addEventListener('click', function (e) {e.preventDefault(); //阻止a标签的默认事件var href = aNode.getAttribute('href');// 手动修改浏览器的地址栏history.pushState(null, '', href);// 通过 history.pushState 手动修改地址栏,// popstate 是监听不到地址栏的变化,所以此处需要手动执行回调函数 PopChangePopChange();}));}function PopChange() {console.log('location', location);switch (location.pathname) {case '/page1':routeView.innerHTML = 'page1';return;case '/page2':routeView.innerHTML = 'page2';return;default:routeView.innerHTML = 'page1';return;}}</script></body>
</html>
同样将上面代码复制到 index.js 文件下替换,效果如下所示:

这就是我们上述提到的 History 模式下,会遇到的麻烦。想要解决这个问题需要配合项目的 Web 服务器如 Express、Koa 等配置服务端返回的内容。
路由使用
接下来我们采用 ES2015 的形式简单讲解 Vue Router 的使用。
引入 Vue-Router
首先是 HTML,我们引入 Vue 和 Vue Router 的静态资源,大家可以去 BootCDN 搜索自己需要的静态资源,下面是 HTML 代码:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script><script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script><title>Vue Router</title></head><body><div id="app"><ul><!-- 使用 router-link 组件来导航. --><!-- 通过传入 to 属性指定链接. --><!-- <router-link> 默认会被渲染成一个 <a> 标签 --><router-link to="/page1">Go to Page1</router-link><br /><router-link to="/page2">Go to Page2</router-link></ul><!-- 路由出口 --><!-- 路由匹配到的组件将渲染在这里 --><router-view></router-view></div><script type="text/javascript">// 1. 定义 (路由) 组件。// 可以从其他文件 import 进来,这里简单写const Page1 = { template: '<div>Page1</div>' };const Page2 = { template: '<div>Page2</div>' };// 2. 定义路由// 每个路由应该映射一个组件。 其中"component" 可以是// 通过 Vue.extend() 创建的组件构造器,// 或者,只是一个组件配置对象。const routes = [{ path: '/page1', component: Page1 },{ path: '/page2', component: Page2 },];// 3. 创建 router 实例,然后传 routes 配置// 你还可以传别的配置参数, 不过先这么简单着吧。const router = new VueRouter({routes: routes,});// 4. 创建和挂载根实例。// 记得要通过 router 配置参数注入路由,// 从而让整个应用都有路由功能const app = new Vue({router: router,}).$mount('#app');</script></body>
</html>
标签和 标签是引入 Vue-Router 后才能使用的,路由匹配到的组件都会渲染在 标签上, 标签用于路由的跳转。
Vue-Router 默认启动 Hash 模式,同样复制到 index.js,重启 node app.js 启动页面的时候,会看到如下所示:

获取全局路由跳转参数的变化
想要全局监听路由的变化,可以在入口页面通过 watch $router对象来实现,修改上述代码:
<script>...
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能。
const app = new Vue({router: router,watch: {$route(to, from) {console.log('to', to)console.log('from', from)}}
}).$mount('#app')...
</script>

添加监听之后,可以拿到 to 和 from 两个参数,to 代表你跳转后的页面参数,from 代表你从哪个页面跳转来的,通过拿到这两个参数,我们就能设置一级二级页面,用于制作过场动画。也可以添加页面顶部的页面加载进度条。
获取路由中带的参数
Page1 页面在跳转的时候带上参数到 Page2,我们如何在 Page2 拿到参数呢?首先我们要给 router-link 标签添加参数,如下所示:
<router-link :to="{path: '/page1', query: { id: 1111 }}">Go to Page1
</router-link>
在 Page1 的模板页面拿到参数:
const Page1 = { template: '<div>Page1 {{ $route.query.id }}</div>' };

重定向页面
这点还是比较重要的,当你输入一个不存在的路由,Vue-Router 无法匹配到的时候,需要默认回到首页,这就要用到重定向匹配,代码如下所示:
const routes = [{ path: '/page1', component: Page1 },{ path: '/page2', component: Page2 },{ path: '*', redirect: '/page1' },
];
这里我们默认 Page1 为首页,当 * 上面的路径都没有被匹配到的时候,就会重新回到 /page1 对应的组件。

以上是 Vue-Router 的一些基础用法,更多深度使用请移步 官方文档详细阅读。
相关文章:
Vue-Router 介绍及路由原理分析
文章目录Vue-Router 路由模式单页面与传统页面跳转的区别Hash 模式History 模式abstract 模式原理解析Hash 模式原理History 模式原理路由使用引入 Vue-Router获取全局路由跳转参数的变化获取路由中带的参数重定向页面Vue-Router 路由模式 单页面与传统页面跳转的区别 单页面…...
git代码提交后jenkins构建和自动部署
利用jenkins和gitlab的webhook结合,实现提交代码之后,自动触发jenkins的构建。顺带介绍一下通过触发器构建,比如直接通过url去触发的方式。 一、jenkins结合webhook 1、jenkins配置 a、首先jenkins得需要安装两个gitlab的插件:(…...
2023面试题目总结
项目遇到的问题难点? 老项目版本过低(angular4),相关框架太少,需要升级成新框架。 1.single-spa 2.qiankun 3.iframe 样式环境隔离/js隔离/公共依赖的加载 JS 原型,原型链,new 原型是存放公共属性地方,所有实例都…...
Vue常用指令及声明周期
文章目录知识点前端开发环境配置v-text && v-htmlv-if、v-else && v-showv-forv-onv-modelv-bind、v-cloak、v-pre&&v-once全局 API 是什么Vue.directive 自定义组件Vue.directive 是什么自定义组件回调函数参数自定义组件的生命周期Vue.set 全局操作为…...
MariaDB 成功敲钟上市 | 它与 Navciat 缘起 10 年前
MariaDB 敲钟上市2022 年底,云数据库公司 MariaDB 与 Angel Pond Holdings 公司完成合并,并在纽交所上市。新公司更名为 MariaDB,MySQL 之父奋斗了13年终敲钟。这标志着 MariaDB 开启新篇章。无论从开源还是商业之路,都将成为业内…...
LESS模型与随机森林
模型学习 1 随机森林 https://blog.csdn.net/weixin_35770067/article/details/107346591? 森林就是建立了很多决策树,把很多决策树组合到一起就是森林。 这些决策树都是为了解决同一任务建立的,最终的目标也都是一致的,最后将其结果来平均…...
如何利用Power Virtual Agents机器人实现成绩查询服务
今天我们继续介绍如何利用Power Virtual Agents来实现成绩查询服务。设计思路是在PVA聊天机器人的对话框中输入学生的姓名和学号来进行成绩的查询。首先,在Microsoft 365的OneDrive中制作一个Excel格式的成绩单。 可以将学生的学号、姓名、各学科成绩进行添加。 在P…...
flavor 配置
文章目录1. flavorDimensions1.1 单维度1.2 多维度2. BuildConfig3. sourceSets4. 参考资料1. flavorDimensions 与 productFlavors 配合使用使用 flavorDimensions 定义风味维度,维度越多,能打出的渠道包越丰富 1.1 单维度 defaultConfig {...flavor…...
《第一行代码》 第五章:详解广播机制
如果你了解网络通信原理应该会知道,在一个 IP 网络范围中最大的IP 地址是被保留作为广播地址来使用的。比如某个网络的 IP 范围是 192.168.0XXX,子网掩码是255.255.255.0那么这个网络的广播地址就是 192.168.0255广播数据包会被发送到同-网络上的所有端口…...
Leetcode(每日一题)——1139. 最大的以 1 为边界的正方形
摘要 1139. 最大的以 1 为边界的正方形 一、以1为边界的最大正方形 1.1 动态规划 第530题需要正方形所有网格中的数字都是1,只要搞懂动态规划的原理,代码就非常简洁。而这题只要正方形4条边的网格都是1即可,中间是什么数字不用管。 这题…...
YOLOv5:GitHub两万八Star项目
来源:投稿 作者:王同学 编辑:学姐 Yolov5详解 官方源码仓库:https://github.com/ultralytics/yolov5 相关论文:未发表(改进点都被你们抢先发了) 0 前言 截止到2022年7月,Yolov5项…...
袋鼠云产品功能更新报告04期丨2023年首次,产品升级“狂飙”
新的一年我们加紧了更新迭代的速度,增加了数据湖平台EasyLake和大数据基础平台EasyMR,超40项功能升级优化。我们将继续保持产品升级节奏,满足不同行业用户的更多需求,为用户带来极致的产品使用体验。 以下为袋鼠云产品功能更新报…...
如何在Power Virtual Agents中使用Power Automate
今天我们来介绍一下如何在Power Virtual Agents中使用PowerAutomate。我们以通过在PVA聊天机器人的对话框中输入“发布通知”后会把预设好的通知信息自动发布到Teams中的某个团队中为例。首先进入PVA聊天机器人编辑界面后选择“主题”-“新建主题”。 在“新建主题”中添加“触…...
BXC6332A第二代智能头盔方案助力电动车市场,为安全保驾护航
随着2020年6月1日起,公安部交管局在全国开展“一盔一带”安全守护行动,摩托车、电动车驾驶人乘车人按照规定正确使用头盔,是保障司乘安全的一道重要屏障,据统计,摩托车、电动自行车驾乘人员死亡事故中约80%为颅脑损伤致…...
浮点数值计算精度丢失问题剖析及解决方法
文章目录1、原因分析2、解决方法2.1、Java中使用 BigDecimal 类2.2、JavaScript 中解决计算精度丢失的问题3、使用建议1、原因分析 首先我们来看个反直觉的浮点数值计算 System.out.println(0.3*3);有的同学可能要问为啥不是0.9? 首先要知道为什么会产生这个问题…...
字符串匹配 - 模式预处理:朴素算法(Naive)(暴力破解)
朴素的字符串匹配算法又称为暴力匹配算法(Brute Force Algorithm),最为简单的字符串匹配算法。算法简介朴素的字符串匹配算法又称为暴力匹配算法(Brute Force Algorithm),它的主要特点是:没有预…...
CVE-2021-42278 CVE-2021-42287域内提权漏洞
漏洞介绍2021 年 11 月 9 日,国外研究员在推特上发布了AD相关的 CVE,CVE-2021-42278 & CVE-2021-42287 ,两个漏洞组合可导致域内普通用户权限提升至域管权限。CVE-2021-42278:是一个安全绕过漏洞,允许通过修改机器…...
关于IcmpSendEcho2的使用和回调问题
由于我的需求是短时间内ping多台机子,所以需要异步执行,微软提供的例子是同步方式的,根据微软官方提供的icmpSendEcho2 函数的信息 ,我需要定义一个空的宏PIO_APC_ROUTINE_DEFINED ,定义完之后,编译又出现…...
XQuery 术语
在 XQuery 中,有七种节点:元素、属性、文本、命名空间、处理指令、注释、以及文档节点(或称为根节点)。 XQuery 术语 节点 在 XQuery 中,有七种节点:元素、属性、文本、命名空间、处理指令、注释、以及文…...
会议论文分享-Security22-状态感知符号执行
Ferry: State-Aware Symbolic Execution for Exploring State-Dependent Program Paths1.引言2.问题陈述与分析2.1.实现状态感知符号执行的挑战2.2.真实程序的特征2.3.Ferry的模型2.3.1.程序状态的定义2.3.2.状态描述变量的特征3.Design3.1.Overview of Ferry3.2.状态描述变量识…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...
