前端路由

朴素地说,路由就是根据不同的url地址来获取资源以显示不同的页面

传统的后端路由就是当URL发生跳转的时候,会重新访问服务器,服务器会解析URL,通过用户请求的url导航到具体的html页面,每次的重新请求响应较慢,会导致用户体验的下降

前端路由则是在URL地址改变时,不再向服务器请求页面,而是通过ajax向服务器请求数据,URL变化能够在无页面刷新的情况下实现UI更新,为用户提供更好的体验

Vue-router

我们直接来使用一下vue-router,感受一下前端路由

在vuecli中创建新项目,注意勾选上vue-router,选完router之后会让你选择是history模式还是hash模式,Y是history模式,n则是hash模式

我们先来创建一个hash模式,创建完毕之后将项目运行起来就可以看到自带的demo,demo包含了两个页面,Home和About,点击顶部的导航栏可以切换

这里呢,就是实现了一个前端路由,home页面和about页面切换的时候没有页面刷新,而是丝滑地变换了UI,而url则是在http://localhost:8080/#/http://localhost:8080/#/about之间切换

然后我们来看一下项目文件

我们可以在views这个文件夹里找到Home和About两个页面,就是两个普通的组件

比起之前的项目,多了一个文件夹router,里面有一个index.js,我将里面的核心代码摘录如下

1
2
3
4
5
6
7
8
9
10
11
12
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]

App.vue中的template内容如下

1
2
3
4
5
6
7
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>

所以使用方法很简单,就是在router/index.js中将路由映射加上去,然后在template中用router-link标签控制做切换控制,router-view标签负责显示对应内容

我们根据这个原理尝试新增一个页内路由,在views中新加一个页面Add.vue

1
2
3
4
5
<template>
<div class="about">
<h1>This is a page for Test</h1>
</div>
</template>

然后在router.js中增加一个映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/test',
name: 'Test',
component: () => import(/* webpackChunkName: "about" */ '../views/Add.vue')
}
]

并在App.vue的导航中增加test链接

1
<router-link to="/test">Test</router-link>

就可以成功地新增一个页面

history模式和hash模式的区别在于,history模式的地址是没有#符号的,比如hash模式是http://localhost:8080/#/about,而在history模式中则是http://localhost:8080/about

而服务器在处理url时,是忽略#后面的内容的,因此hash模式是可以直接使用的,而history模式则需要后端的配合(不刷新页面)

此外,hash模式和history模式在vuecli代码上的唯一区别就是history模式在router/index.js这个文件里面多了一行代码

hash模式是

1
2
3
const router = new VueRouter({
base: process.env.BASE_URL,routes
})

而history模式是

1
2
3
4
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL, routes
})

创建的history模式,只要将这句话注释了,就和hash模式一样了

自己实现前端路由功能

知道#不会引起页面刷新这个原理之后自己实现前端路由就十分地简单,站在vue这个巨人的肩膀上就更简单了

基本思路就是利用带#的url后缀使得页面不会自动刷新,利用动态组件功能来根据url后缀改变页面显示内容,#以及之后的内容也就是所谓的哈希值会被记录在location.hash中,我们可以监听hashchange事件来获取url后缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<div id="app">
<a href="#/home">Home</a> |
<a href="#/about">About</a> |
<a href="#/test">Test</a>

<component :is="page"></component>
</div>
</template>

<script>
import home from "./components/Home.vue";
import about from "./components/About.vue";
import test from "./components/Add.vue";

export default {
name: "App",
data: function () {
return {
page: null,
};
},
// 挂载后开始监听hashchange事件
mounted() {
let pages = {
home,
about,
test,
};
let that = this;
// 监听hashchange
window.addEventListener("hashchange", function (evt) {
// 截取有用信息
var str = location.hash.slice(2, location.hash.length);
// console.log(this) 如果是箭头函数的话这里可以直接用this
that.page = pages[str];
});
// 没有hashchange时 (直接访问对应地址时)
var str = location.hash.slice(2, location.hash.length);
this.page = pages[str];
},
components: {
home,
about,
test,
},
};
</script>