前言
本文是手写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
设置了一个 id
,id
的值为 html
。
并且在页面当中添加了两个 a 标签,两个 a 标签的 href 分别跳转地址为,一个是 #/home
,一个是 #/about
。
html
<!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 值。
javascript
<script>
window.addEventListener('hashchange', () => {
console.log('当前的hash值发生了变化');
});
</script>
好了,我们打开浏览器,然后点击首页,我们可以看到控制台打印了一句话,说明我们的 hash 值发生了变化,看到这一点就可以验证我的一个说法。
接下来我们要做的就是将内容渲染到 div
中,我们先简单的来将 hash 值写入到 div
中。
javascript
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
事件。
javascript
window.addEventListener('load', () => {
const currentHash = location.hash.slice(1);
document.querySelector('#html').innerHTML = currentHash;
});
我们打开浏览器,我们可以看到我们的容器当中显示的是 home
,这样我们就解决了第一次打开页面的时候,我们的容器显示的是空的这个问题。
路径
到此为止,我们就可以监听 hash 的变化了,那么我们怎么监听路径的变化呢?我们可以使用 history
的 pushState
方法,这个方法可以改变路径,然后我们就可以监听路径的变化了。
在看路径地址之前,我们先将基本的代码页面结构搭建一下,路径与之前的 hash 是不一样的,所以我们这里的 a 标签就不能使用 href 属性了,路径我们可以给 a 标签绑定一个事件,绑定一个方法然后在这个方法当中来改变路径。
页面样式的基本结构代码如下:
html
<!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
方法当中,这样我们就可以改变路径了。
javascript
history.pushState(null, null, path);
好了,我们打开浏览器,点击首页,我们可以看到我们的路径变成了 http://localhost:8080/home
,点击关于,我们可以看到我们的路径变成了 http://localhost:8080/about
。
没问题之后,我们再将内容渲染到 div
中,我们可以在 go
方法当中,获取到当前的路径,然后将路径写入到 div
中。
javascript
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
中。
javascript
window.addEventListener('popstate', () => {
document.querySelector('#html').innerHTML = location.pathname;
});
测试注意点
我们打开浏览器,点击首页,我们可以看到我们的容器当中显示的是 home
,点击关于,我们可以看到我们的容器当中显示的是 about
,好,这个时候我们的关键点就要来了,我们点击一下浏览器的前进与后退,我们可以看到我们的容器当中显示的是 home
与 about
,这样我们就解决了这个问题。
总结
到此为止,我们了解了如何监听 hash 与路径的变化,并且了解到了如何监听前进与后退的点击,hash 与路径的变化。
本篇文章就到这里,感谢大家的阅读,如果有什么不足的地方,欢迎大家指出,我会及时的进行修改。