前言

本文是手写Vue-Router的第一篇,主要是对Vue-Router的知识储备,为后面的手写做准备。

那么 VueRouter 怎么实现呢?要想实现 VueRouter,首先要知道 VueRouter 它的本质是什么。

VueRouter 的本质

VueRoute 的本质是什么?VueRouter 的本质就是根据 "不同的 hash 值" 或者 "不同的路径地址", 将不同的内容渲染到 router-view 中。

再过去,我学习 VueRouter 的时候,知道 VueRouter 有两种模式,一种是 hash 模式,一种是 history 模式。那么这两种模式有什么区别呢?

hash 模式和 history 模式的区别

如果是 history 模式,那么我们的路径就是这样的:http://localhost:8080/home,如果是 hash 模式,那么我们的路径就是这样的:http://localhost:8080/#/home

了解了这些知识之后,所以实现 VueRouter 的核心关键点就在于如何监听 'hash''路径' 的变化, 再将不同的内容写到 router-view 中。

那么在实现 VueRouter 之前呢,我在给大家补充一下,如何监听 'hash''路径' 的变化。

如何监听 hash 或 路径 的变化

hash

首先我新建了一个 test.html 文件,然后在里面写了一个 div,然后给这个 div 设置了一个 idid 的值为 html

并且在页面当中添加了两个 a 标签,两个 a 标签的 href 分别跳转地址为,一个是 #/home,一个是 #/about

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="#/home">首页</a>
<a href="#/about">关于</a>
<div id="html"></div>
</body>
</html>

基本的结构我们搭建完毕,好了接下来我们怎么监听 hash 的变化呢?也非常的简单,其实在我们原生的 JS 当中,有一个 hashchange 事件,这个事件就是用来监听 hash 变化的(专门用于监听 hash 变化的)。

那么知道了监听 hash 变化的事件之后,我们怎么使用呢?我们可以给 window 绑定一个 hashchange 事件,然后在这个事件当中,有一个回调函数,主要 hash 变化之后,我们就可以在这个回调函数当中,获取到当前的 hash 值。

那么怎么验证它会执行这个回调函数呢,我们可以在这个回调函数当中,打印一下当前的 hash 值。

<script>
window.addEventListener('hashchange', () => {
console.log('当前的hash值发生了变化');
});
</script>

好了,我们打开浏览器,然后点击首页,我们可以看到控制台打印了一句话,说明我们的 hash 值发生了变化,看到这一点就可以验证我的一个说法。

接下来我们要做的就是将内容渲染到 div 中,我们先简单的来将 hash 值写入到 div 中。

window.addEventListener('hashchange', () => {
const currentHash = location.hash.slice(1); document.querySelector('#html').innerHTML = currentHash;
});

我们打开浏览器,点击首页,我们可以看到 div 中的内容变成了 home,点击关于,我们可以看到 div 中的内容变成了 about

将来我们是不是根据这个获取到对应的组件,然后将组件渲染到 div(某一个容器当中)中就可以了。

好了到这里我们的监听 hash 就可以,可以了之后还没完,可以了之后有没有这么一种情况,就是我们第一次打开页面的时候我们地址上面是没有 hash 值的,还有可能就是我们地址栏是有 hash 值的这种情况,是不是有可能,对吧,我们先来看看我们第一次打开页面的时候,有 hash 值我们的容器显示的是什么。

我们可以看到我们的容器显示的是空的,那么我们怎么解决这个问题呢?我们可以在页面加载的时候,手动的触发一次 hashchange 事件,这样我们就可以在页面加载的时候,将内容渲染到 div 中。

首先我们在 window 上面绑定一个 load 事件,然后在这个事件当中,我们手动的触发一次 hashchange 事件。

window.addEventListener('load', () => {
const currentHash = location.hash.slice(1);
document.querySelector('#html').innerHTML = currentHash;
});

我们打开浏览器,我们可以看到我们的容器当中显示的是 home,这样我们就解决了第一次打开页面的时候,我们的容器显示的是空的这个问题。

路径

到此为止,我们就可以监听 hash 的变化了,那么我们怎么监听路径的变化呢?我们可以使用 historypushState 方法,这个方法可以改变路径,然后我们就可以监听路径的变化了。

在看路径地址之前,我们先将基本的代码页面结构搭建一下,路径与之前的 hash 是不一样的,所以我们这里的 a 标签就不能使用 href 属性了,路径我们可以给 a 标签绑定一个事件,绑定一个方法然后在这个方法当中来改变路径。

页面样式的基本结构代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a onclick="go('/home')">首页</a>
<a onclick="go('/about')">关于</a>
<div id="html"></div>
<script>
function go(path) {
}
</script>
</body>
</html>

定义了一个 go 方法,接收一个参数 path,接下来要做的事情就是根据这个 path 来改变路径,这个我们要怎么实现呢?这里我们可以借助一个 history 对象,在 history 对象当中有一个 pushState 方法,这个方法接收三个参数,第一个参数是 state,第二个参数是 title,第三个参数是 url

pushState 方法参数:

  • state:一个与指定网址相关的状态对象,popstate 事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填 null。
  • title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填 null。
  • url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。

那么我们怎么使用呢?我们可以在 go 方法当中,调用 pushState 方法,然后将 path 传入到 pushState 方法当中,这样我们就可以改变路径了。

history.pushState(null, null, path);

好了,我们打开浏览器,点击首页,我们可以看到我们的路径变成了 http://localhost:8080/home,点击关于,我们可以看到我们的路径变成了 http://localhost:8080/about

没问题之后,我们再将内容渲染到 div 中,我们可以在 go 方法当中,获取到当前的路径,然后将路径写入到 div 中。

document.querySelector('#html').innerHTML = path;

我们打开浏览器,点击首页,我们可以看到我们的容器当中显示的是 home,点击关于,我们可以看到我们的容器当中显示的是 about

到此为止,我们就可以监听路径的变化了,好了知道这些内容之后,还有一个注意点需要给大家说一下:

注意点

我们先基于 IDEA 运行我们的项目,然后,点击一下首页这个时候我们的路径与容器内容都是 /home, 好,我们这个时候将地址复制一下,例如现在路径已经变为了 http://localhost:63342/home ,我们在点击一下关于,我们可以看到我们的路径变为了 http://localhost:63342/about, 好,这个时候我们的关键点就要来了:

正如上图所示,我们的路径变为了 http://localhost:63342/home, 但是容器的内容还是 about,这是为什么呢?所以说这个东西我们也需要进行同步一下,那么我们手动添加了路径那么它怎么知道我们有没有前进与后退呢?非常简单,其实在我们的原生 JS 当中,又有一个事件,这个事件就是 popstate 事件,通过这个事件,我们就可以监听到前进与后退的点击,通过这个事件监听了前进与后退的点击之后,它会执行一个回调函数,我们在这个回调函数当中,就可以处理之前的问题了。

更改我们的代码,我们可以在 window 上面绑定一个 popstate 事件,然后在这个事件当中,我们可以获取到当前的路径,然后将路径写入到 div 中。

window.addEventListener('popstate', () => {
document.querySelector('#html').innerHTML = location.pathname;
});

测试注意点

我们打开浏览器,点击首页,我们可以看到我们的容器当中显示的是 home,点击关于,我们可以看到我们的容器当中显示的是 about,好,这个时候我们的关键点就要来了,我们点击一下浏览器的前进与后退,我们可以看到我们的容器当中显示的是 homeabout,这样我们就解决了这个问题。

总结

到此为止,我们了解了如何监听 hash 与路径的变化,并且了解到了如何监听前进与后退的点击,hash 与路径的变化。

本篇文章就到这里,感谢大家的阅读,如果有什么不足的地方,欢迎大家指出,我会及时的进行修改。

手撕Vue-Router-知识储备的更多相关文章

  1. 【Vuejs】350- 学习 Vue 源码的必要知识储备

    前言 我最近在写 Vue 进阶的内容.在这个过程中,有些人问我看 Vue 源码需要有哪些准备吗?所以也就有了这篇计划之外的文章. 当你想学习 Vue 源码的时候,需要有扎实的 JavaScript 基 ...

  2. 「进阶篇」Vue Router 核心原理解析

    前言 此篇为进阶篇,希望读者有 Vue.js,Vue Router 的使用经验,并对 Vue.js 核心原理有简单了解: 不会大篇幅手撕源码,会贴最核心的源码,对应的官方仓库源码地址会放到超上,可以配 ...

  3. 前端MVC Vue2学习总结(八)——Vue Router路由、Vuex状态管理、Element-UI

    一.Vue Router路由 二.Vuex状态管理 三.Element-UI Element-UI是饿了么前端团队推出的一款基于Vue.js 2.0 的桌面端UI框架,手机端有对应框架是 Mint U ...

  4. python 全栈开发,Day91(Vue实例的生命周期,组件间通信之中央事件总线bus,Vue Router,vue-cli 工具)

    昨日内容回顾 0. 组件注意事项!!! data属性必须是一个函数! 1. 注册全局组件 Vue.component('组件名',{ template: `` }) var app = new Vue ...

  5. vue路由知识整理

    vue路由知识整理 对于单页应用,官方提供了vue-router进行路由跳转的处理.我们已经可以通过组合组件来组成应用程序,当你要把 vue-router 添加进来,我们需要做的是,将组件(compo ...

  6. [Vue 牛刀小试]:第十四章 - 编程式导航与实现组件与 Vue Router 之间的解耦

    一.前言 在上一章的学习中,通过举例说明,我们了解了 Vue Router 中命名路由.命名视图的使用方法,以及如何通过 query 查询参数传参,或者是采用 param 传参的方式实现路由间的参数传 ...

  7. NN入门,手把手教你用Numpy手撕NN(一)

    前言 这是一篇包含极少数学推导的NN入门文章 大概从今年4月份起就想着学一学NN,但是无奈平时时间不多,而且空闲时间都拿去做比赛或是看动漫去了,所以一拖再拖,直到这8月份才正式开始NN的学习. 这篇文 ...

  8. 8. Vue - Router

    一.Vue Router 的使用 JavaScript: 1.创建组件:创建单页面应用需要渲染的组件 2.创建路由:创建VueRouter实例 3.映射路由:调用VueRouter实例的map方法 4 ...

  9. 「vue基础」一篇浅显易懂的 Vue 路由使用指南( Vue Router 上)

    大家好,今天的内容,我将和大家一起聊聊 Vue 路由相关的知识,如果你以前做过服务端相关的开发,那你一定会对程序的URL结构有所了解,我没记错的话也是路由映射的概念,需要进行配置. 其实前端这些框架的 ...

  10. Vue大概知识体系和学习参考

    Vue大概知识体系和学习参考文档 官方文档学习,参考,借鉴地址:https://cn.vuejs.org/v2/guide/installation.html 菜鸟教程:https://www.run ...

随机推荐

  1. python移动文件

    #移动文件(目录) shutil.move("oldpos","newpos") shutil.move("D:/知乎日报/latest/一张优惠券, ...

  2. spring-mvc系列:简介和基本使用

    目录 一.简介 1.什么是MVC 2.什么是SpringMVC 3.SpringMVC的特点 二.基本使用 1.开发环境 2.创建maven工程 3.配置web.xml 4.创建SpringMVC的配 ...

  3. quarkus依赖注入之十二:禁用类级别拦截器

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<quarkus依赖注入> ...

  4. 记一次MySql灾难性事件

    2023年8月8日,本来系一个风和日丽的夏天中的平凡一天,但这种平凡,注定住佢一定唔平凡,唉...现在回忆起都阵阵咁痛!!! 重要嘅事情讲三次,唔好手贱,唔好手贱,唔好手贱 事日,如常上班,本人系一名 ...

  5. 部署Harbor镜像仓库

    Harbor介绍 Harbor是一个开源的企业级容器注册表服务.它由VMware和Pivotal联合开发,旨在为云原生应用程序提供一种安全可靠的容器镜像管理解决方案. Harbor是一个功能丰富.安全 ...

  6. Tarjan基础用法

    \(\operatorname{Tarjan}\) 基础用法 目录 \(\operatorname{Tarjan}\) 基础用法 \(\operatorname{Tarjan}\) 求最近公共祖先 前 ...

  7. 《Kali渗透基础》11. 无线渗透(一)

    @ 目录 1:无线技术 2:IEEE 802.11 标准 2.1:无线网络分层 2.2:IEEE 2.3:日常使用标准 2.3.1:802.11 2.3.2:802.11b 2.3.3:802.11a ...

  8. KRPANO资源分析工具下载四方环视全景图

    提示:目前分析工具中的全景图下载功能将被极速全景图下载大师替代,相比分析工具,极速全景图下载大师支持更多的网站(包括各类KRPano全景网站,和百度街景) 详细可以查看如下的链接: 极速全景图下载大师 ...

  9. 解决Promise的多并发问题

    提起控制并发,大家应该不陌生,我们可以先来看看多并发,再去聊聊为什么要去控制它 多并发一般是指多个异步操作同时进行,而运行的环境中资源是有限的,短时间内过多的并发,会对所运行的环境造成很大的压力,比如 ...

  10. Solution -「ZJOI 2014」力

    Descrption Link. 对于每一个 \(i\),求出: \[\sum_{j=1}^{i-1}\frac{a_{j}}{(i-j)^{2}}-\sum_{j=i+1}^{n}\frac{a_{ ...