当前位置: 首页 > news >正文

vue中router路由的原理?两种路由模式如何实现?(vue2) -(上)

平时我们编写路由时,通常直接下载插件使用,在main.js文件中引入直接通过引入vue-router中的Router通过Vue.use使用以后定义一个routeMap数组,里边是我们编写路由的地方,最后通过实例化一个 Router实例 将routes=我们定义的routeMao路由数组。

但是我们并不知道它是如何实现的,因此我们可以通过自己编写插件的形式,实现一个vue-router

常用路由步骤:

//router/index.js
import Vue from 'vue'import Router from 'vue-router'Vue.use(Router)export const routeMap= [{path: '/home',component: () => import('../components/Home/Home.vue')},{path: '/list',component: () => import('../components/List/List.vue')},
]const router = new Router({routes: constantRouterMap
})export default router//main.js
import router from './router'new Vue({router,store,render: h => h(App),
}).$mount('#app')

我们来实现一下如何实现一个hash模式的路由

由于我们不适用插件形式实现,因此我们使用步骤与平常实现有一些差异。

router/index.js是我们的路由文件,里面放置我们的路由

plugin/router.js是我们的自定义插件文件,里面放置我们自定义插件内容

components是我们组件目录,放置我们的路由组件(通常使用view定义路由组件)

main.js是我们的入口文件,需要在该文件引入router并且实例化vue的时候需要将引入的router使用

1、首先我们在App.vue文件中,通过<router-view/>以及<router-link/>定义声明式导航和路由占位

<div><router-link to="/home">首页</router-link><router-link to="/list">列表</router-link><hr><router-view></router-view>
</div>

这里我们会发现使用以后会报错,因为我们没有下载插件,因此没有这两个组件。

我们需要配置plugin插件

由于没有这两个全局组件因此我们需要配置两个全局组件

install方法是为了将我们的路由挂载在我们的组件实例上,通过mixin全局混入,将我们的实例上挂载$router属性

然后定义两个全局组件,router-link由于它渲染出来相当于html中的a标签,使用render方法,参数为一个createElement方法接收三个参数(第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容)

router-view由于是一个路由占位符,因此返回的是个组件,渲染组件。

通过routesMap是我们存放的路由,current是我们的当前的path路由,因此可以通过查找路由中key值为我们当前path路径的,查找到我们的组件。通过return渲染我们的组件

VueRouter.install = function (_Vue) {//1、保存VueVue = _Vue//2、将以下代码延迟到vue实例初始化完毕执行Vue.mixin({beforeCreate() {//判断如果有router属性就执行下方代码if (this.$options.router) {Vue.prototype.$router = this.$options.router;}}})//创建全局组件router-link和router-view//创建router-link组件Vue.component('router-link', {props: {to: {type: String | Object,required: true}},render(h) {// h 有三个参数,第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)}})//创建router-view组件Vue.component('router-view', {// 组件要重新渲染,必须要让数据发生改变的时候,重新去执行render函数render(h) {const router = this.$routerconsole.log(router.routesMap, 'routesMap');let component = router.routesMap[router.current];//组件//获取到外部传递的路由表return h(component)}})
}

2、我们定义一个路由类,该类会获取到我们的路由信息从而进行路由监听以及组件渲染。

(1)、该类中constructor是我们通过实例化vueRouter传入的数据,我们需要通过将数据保存在vueRouter实例上,获取到当前的url path路径。

(2)、通过监听方法hashchange监听我们hash值的变化,通过方法进行监听,但是一定要注意这里方法的this指向必须是vueRouter实例不可以是window,因此需要通过bind改变this指向

(3)、通过defineReactive来讲我们的path路径变为响应式,这样每次路径发生变化可以监测到变化。

(4)、定义routesMap为我们的路由对象,遍历我们传入的路由数组,将我们每个path路径对应组件,为一组一组的键值对。

这样可以实现一套hash路由模式的路由跳转。

全部代码如下:

//plugin/router.js
let Vue;class VueRouter {constructor(options) {//保存选项this.options = options;// console.log(options, '路由数据');// 定义一个响应式的变量current,保存当前的hash值let url = location.hash.slice(1,) || '/';// defineReactive定义响应式的对象Vue.util.defineReactive(this, 'current', url)// hashchange事件来监听hash值的变化, 注意this指向问题addEventListener('hashchange', this.changeHash.bind(this))this.routesMap = {};//对routes中的对象做一个映射:routesMap = {'/home':component,'/list': component}this.options.routes.forEach(route => {this.routesMap[route.path] = route.component})}//监听hash值变化的函数changeHash() {//通过location.hash来获取到hash值this.current = location.hash.slice(1,)console.log(this.routesMap, '555');// console.log(this.current);//当前path路径}
}VueRouter.install = function (_Vue) {//1、保存VueVue = _Vue//2、将以下代码延迟到vue实例初始化完毕执行Vue.mixin({beforeCreate() {//判断如果有router属性就执行下方代码if (this.$options.router) {Vue.prototype.$router = this.$options.router;}}})//创建全局组件router-link和router-view//创建router-link组件Vue.component('router-link', {props: {to: {type: String | Object,required: true}},render(h) {// h 有三个参数,第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)}})//创建router-view组件Vue.component('router-view', {// 组件要重新渲染,必须要让数据发生改变的时候,重新去执行render函数render(h) {const router = this.$routerconsole.log(router.routesMap, 'routesMap');let component = router.routesMap[router.current];//组件console.log(component, 'component');//获取到外部传递的路由表return h(component)}})
}export default VueRouter;

接下来实现历史路由模式

我们知道历史路由模式和hash路由模式区别是域名是否存在#因此我们可以通过在路由文件中定义mode属性判断是历史路由模式还是hash路由模式。

先大白话来说一下大概的实现思路(hash和history实现区别):

1、我们通过我们定义的mode判断是hash路由模式还是history路由模式,router-link点击跳转的时候如果是hash路由模式,我们通过render方法返回我们渲染到浏览器域名的数据,hash模式是带#的,因此我们定义href属性需要+#,但是history模式是不带#的,因此我们不需要加#。其次,因为hash模式自动检测我们的域名,因此我们实现历史模式需要手动加一个点击事件,并且需要阻止a链接默认跳转的行为(preventDefault取消默认行为),并且通过pushState方法,实现跳转,这是历史路由模式的方法pushState(obj,title,url),最后设置我们的路由当前path路径为我们跳转的路径。

2、当我们定义好它的router-link全局组件以后,这时我们hash路由模式和history路由模式已经可以基本实现,hash模式带#,history路由模式不带#。但是我们仍要定义一个监听历史路由模式变化的监听事件。这里我们通过mode判断是什么模式从而监听不同的事件,历史路由模式监听需要通过监听popState方法,来判断是否发生变化,它坚挺的是我们浏览器的前进后退的变化。

历史路由模式监听事件为hashchange方法,这个事件是用来监听我们hash值的变化,通过设置两个方法从而设置我们当前路径为对应的path路径。hash模式会通过slice剪切到#,历史路由模式则通过location.pathname获取到当前path路径。

实现如下:

let Vue;class VueRouter {constructor(options) {//保存选项this.options = options;// console.log(options, '路由数据');// 定义一个响应式的变量current,保存当前的hash值let url = location.hash.slice(1,) || '/';// defineReactive定义响应式的对象Vue.util.defineReactive(this, 'current', url)//判断当前的路由模式if (this.options.mode === 'hash') {// hashchange事件来监听hash值的变化, 注意this指向问题addEventListener('hashchange', this.changeHash.bind(this))} else if (this.options.mode === 'history') {// history模式监听的事件叫做:popstate, 监听的是浏览器左上角的两个小箭头的变化addEventListener('popstate', this.changeHistory.bind(this))}this.routesMap = {};//对routes中的对象做一个映射:routesMap = {'/home':component,'/list': component}this.options.routes.forEach(route => {this.routesMap[route.path] = route.component})}//监听hash值变化的函数changeHash() {//通过location.hash来获取到hash值this.current = location.hash.slice(1,)console.log(this.routesMap, '555');// console.log(this.current);//当前path路径}// historychangeHistory() {// console.log(location.pathname)this.current = location.pathname;}}

VueRouter.install = function (_Vue) {//1、保存VueVue = _Vue//2、将以下代码延迟到vue实例初始化完毕执行Vue.mixin({beforeCreate() {//判断如果有router属性就执行下方代码if (this.$options.router) {Vue.prototype.$router = this.$options.router;}}})//创建全局组件router-link和router-view//创建router-link组件Vue.component('router-link', {props: {to: {type: String | Object,required: true}},render(h) {// h 有三个参数,第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容const router = this.$router;if (router.options.mode === 'hash') {return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)} else if (router.options.mode === 'history') {return h('a', {attrs: { href: this.to },on: {'click': ev => {// 1. 阻止a链接的默认跳转行为ev.preventDefault()// 2. 调用pushState方法来实现跳转: pushState(obj, title, url)history.pushState({}, '', this.to)// 3. 设置current的值router.current = this.to;}}}, this.$slots.default)}}})//创建router-view组件Vue.component('router-view', {// 组件要重新渲染,必须要让数据发生改变的时候,重新去执行render函数render(h) {const router = this.$routerconsole.log(router.routesMap, 'routesMap');let component = router.routesMap[router.current];//组件console.log(component, 'component');//获取到外部传递的路由表return h(component)}})
}

这一期我们讲解了,如何实现一个基本的hash路由模式以及history路由模式,但是我们通常使用情况下路由嵌套通过一级路由下定义children属性来定义二级路由,这并没有实现,下一期来实现路由嵌套。

相关文章:

vue中router路由的原理?两种路由模式如何实现?(vue2) -(上)

平时我们编写路由时&#xff0c;通常直接下载插件使用&#xff0c;在main.js文件中引入直接通过引入vue-router中的Router通过Vue.use使用以后定义一个routeMap数组&#xff0c;里边是我们编写路由的地方&#xff0c;最后通过实例化一个 Router实例 将routes我们定义的routeMao…...

消息队列(3) -封装数据库的操作

前言 上一篇博客我们写了, 关于交换机, 队列,绑定, 写入数据库的一些建库建表的操作 这一篇博客中,我们将建库建表操作,封装一下实现层一个类来供上层服务的调用 , 并在写完该类之后, 测试代码是否完整 实现封装 在写完上述的接口类 与 xml 后, 我们想要 创建一个类 ,来调用…...

PostgreSQL中根据时间段范围查询数据,如19:29:10到20:29:10范围内的数据,排除年月日

数据格式如下 问题描述 我的SQL语句条件是 WHERE (TO_CHAR(cti.binder_gen_time, YYYY-MM-DD HH:mm:ss) > 19:29:10 AND TO_CHAR(cti.binder_gen_time, YYYY-MM-DD HH:mm:ss) < 20:29:10)为什么我数据的时间是2023-07-20 17:58:29也能被查出来&#xff1f; 问题解决…...

【二分+贪心】CF1665 C

Problem - C - Codeforces 题意&#xff1a; 思路&#xff1a; 一开始想太简单wa6了 只想到先感染大的分量&#xff0c;然后最后把最大的分量剩下的染色 但是可能会有别的分量更大&#xff08;因为最后给最大的染色之后可能不再是最大的&#xff09; 可以用堆维护&#xf…...

【Wamp】安装 | 局域网内设备访问

安装教程&#xff1a; https://wampserver.site/article/1.html 下载 https://www.wampserver.com/en/ 安装路径上不能有中文 安装好之后图标呈绿色 放入网页文件 将网页文件放置于wamp文件夹的www子文件夹 例如&#xff1a;\Wamp\program\www 修改http端口 WAMP服务器…...

【golang】类型推断和变量重声明

类型推断是一种编程语言在编译期自动解释表达式类型的能力。 1.Go语言的类型推断可以带来哪些好处&#xff1f; 在写代码时&#xff0c;我们通过使用Go语言的类型推断会节省敲击次数&#xff0c;而节省下来的键盘敲击次数几乎可以忽略不记。但它真正的好处&#xff0c;往往会…...

“算法详解”系列第3卷贪心算法和动态规划出版

“算法详解”系列图书共有4卷&#xff0c;目前1到3卷已经出版。最新出版的是第3卷—贪心算法和动态规划。 算法详解 卷3 贪心算法和动态规划 “算法详解”系列图书共有4卷&#xff0c;本书是第3卷—贪心算法和动态规划。其中贪心算法主要包括调度、最小生成树、集群、哈夫曼编…...

CSS前端开发指南:创造精美的用户界面

简介&#xff1a; 《CSS前端开发指南&#xff1a;创造精美的用户界面》是一本旨在帮助读者掌握CSS技术&#xff0c;实现令人惊叹的前端用户界面的实用指南。无论您是初学者还是有经验的开发者&#xff0c;本书都将为您提供全面的知识和实用技巧&#xff0c;帮助您创建引人注目…...

代数学与理论物理中常见的群

代数学与理论物理中常见的群 代数学与理论物理中常见的群 四阶群 六阶群 对称群 二维转动群 三维转动群 三维正交群 群 O3群...

解析xml文件,获取需要的数据并写入txt文件中

_ 话不多说&#xff01;直接上代码&#xff01;_ 1、XmlUtil.java xml解析工具类 public class XmlUtil {private static String dicName "";private static String dicValue "";// 用于存储需要的数据private static List<Map<String, Str…...

JavaScript基础 第三天

1.for循环 2.数组的基本使用和操作 3.数组排序 一.for循环 ① 语法&#xff1a;把声明起始值&#xff0c;循环条件&#xff0c;变量值写到一起&#xff0c;让人一目了然 for(变量起始值;终止条件;变量变化量) {// 循环体 }举例&#xff1a; for (let i 0; i < 100; i)…...

2.Redis部署到Windows服务器

1.下载安装包 Redis官网没有提供Windows的安装包&#xff0c;可以去gitHub或者网上去下载Redis的Windows安装包。 2.Redis部署到服务器 将Redis整个文件夹放到服务器的指令目录&#xff0c;然后进行修改Redis的配置文件 redis.windows.conf&#xff0c;修改里面的配置项 1.b…...

【修正-高斯拉普拉斯滤波器-用于平滑和去噪】基于修正高斯滤波拉普拉斯地震到达时间自动检测研究(Matlab代码实现)

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

Go语言基础: 有参函数Func、Map、Strings详细案例教程

目录标题 一、Variadic Functions1.Syntax2.Examples and understanding how variadic functions work3.Slice arguments vs Variadic arguments 仅改变可变参数4.Gotcha 二、Map1.Create a Map2.Retrieving value for a key from a map3.Checking if a key exists4.Iterate ov…...

JDBC连接数据库如何实现你会吗???

1.首先建立一个maven项目。。。详细过程来了哇 还没有安装maven的童鞋可以看这里&#xff1a;maven的下载安装与配置环境变量&#xff01;&#xff01;&#xff01;&#xff08;全网最详细&#xff09;_明天更新的博客-CSDN博客 有很多小伙伴就有疑问啦&#xff0c;难道我直接…...

C#与C++交互(2)——ANSI、UTF8、Unicode文本编码

【前言】 我们知道计算机上只会存储二进制的数据&#xff0c;无论文本、图片、音频、视频等&#xff0c;当我们将其保存在计算机上时&#xff0c;都会被转成二进制的。我们打开查看的时候&#xff0c;二进制数据又被转成我们看得懂的信息。如何将计算机上的二进制数据转为我们…...

SQLSTATE[42000]: this is incompatible with sql_mode=only_full_group_by in

执行 SELECT *FROM test WHERE id>1 GROUP BY name having AVG(age)>10 ORDER BY id desc limit 1 提示错误 Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause…...

企业权限管理(五)-订单分页

订单分页查询 PageHelper介绍 PageHelper是国内非常优秀的一款开源的mybatis分页插件&#xff0c;它支持基本主流与常用的数据库&#xff0c;例如mysql、oracle、mariaDB、DB2、SQLite、Hsqldb等。 PageHelper使用 集成 引入分页插件有下面2种方式&#xff0c;推荐使用 Maven …...

Blender如何给fbx模型添加材质贴图并导出带有材质贴图的模型

推荐&#xff1a;使用 NSDT场景编辑器快速助你搭建可二次编辑的3D应用场景 此教程适合新手用户&#xff0c;专业人士直接可直接绕路。 本教程中介绍了利用Blender建模软件&#xff0c;只需要简单几步就可以为模型添加材质贴&#xff0c;图&#xff0c;并且导出带有材质的模型文…...

MySQL不走索引的情况分析

未建立索引 当数据表没有设计相关索引时&#xff0c;查询会扫描全表。 create table test_temp (test_id int auto_incrementprimary key,field_1 varchar(20) null,field_2 varchar(20) null,field_3 bigint null,create_date date null );expl…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

npm安装electron下载太慢,导致报错

npm安装electron下载太慢&#xff0c;导致报错 背景 想学习electron框架做个桌面应用&#xff0c;卡在了安装依赖&#xff08;无语了&#xff09;。。。一开始以为node版本或者npm版本太低问题&#xff0c;调整版本后还是报错。偶尔执行install命令后&#xff0c;可以开始下载…...