# Vue 路由的应用

# 1.Vue-router 基本应用,多级路由

# 1.1 基本路由

1. 导入 vue-router 包。注意:vue-router3 版本为 vue2 使用,vue-router4 版本为 vue3 使用,错误版本会报错

1
yarn add vue-router@3

2. 在 main.js 中应用插件 Vue.use(VueRouter)

3. 在 src 下新建 router 文件夹,编写配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import VueRouter from 'vue-router'

import About from '../components/About.vue'
import Hello from '../components/HelloWorld.vue'

export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/hello',
component: Hello,
}
]
})

4. 在 main.js 中全局引用配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from './router'

Vue.config.productionTip = false
Vue.use(VueRouter)


new Vue({
render: h => h(App),
router:router,
}).$mount('#app')

5. 样式的点击、选中切换

1
2
<router-link class="item" active-class="active" to="/about">About</router-link>
<router-link class="item" active-class="active" to="/hello">Home</router-link>

此处 <router-link> 会被浏览器自动切换成 a 标签,to 中写的为 router 配置项中配置的路径,跳转至目标组件

6. 指定展示位

1
<router-view></router-view>

以下为组件的展示

App.vue

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
49
50
51
52
<template>
<div id="app">
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Vue Router Demo</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/hello">Home</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<router-view></router-view>
<!-- <About/> -->
</div>
</div>
</div>
</div>
</div>
</div>
</template>

<script>
import Hello from './components/Hello.vue'
import About from './components/About.vue'

export default {
name: 'App',
components: {
Hello,
About
}
}
</script>

<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Hello.vue

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
我是Hello的内容
</div>
</template>

<script>
export default {
name:'About',
}
</script>

About.vue

1
2
3
4
5
6
7
8
9
10
11
<template>
<div>
我是About的内容
</div>
</template>

<script>
export default {
name:'About',
}
</script>

# 1.2 多级路由

多级路由在普通路由的基础上相当简单,只需要在普通路由下再加上 children 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
path: '/hello',
component: Hello,
children: [
{
path: 'news',
component:News,
},
{
path: "massages",
component:Messages
}
]
}

需要注意的是,children 中的 path 不需要加上 /

在路由的调用时需要加上前置的所有父级路径

1
<router-link class="list-group-item" active-class="active" to="/hello/news">News</router-link>

# 1.3 一些注意事项

1. 每次路由的调用都是一个对象生成和销毁的过程

2. 通常普通组件放在 components 文件夹里,路由组件放在 views 文件夹里

3. 每个组件都有自己的 $route 属性,储存自己的路由信息

4. 每个应用都有 $router 属性

# 2.query params props 属性 与命名路由的使用

# 2.1 query

在父组件中传值

1
2
3
4
5
6
7
8
9
10
11
12
13
<router-link class="list-group-item" active-class="active" :to="{
path:'/hello/news',
query:{
id:Massages.title,
game:Massages.game
}
}">News</router-link>

data(){
return{
Massages:{title:'sb',game:"永劫无间"}
}
}

子组件接收数据

1
2
3
4
5
6
7
8
9
<template>
<div>
<ul>
<li>{{$route.query.id}}</li>
<li>{{$route.query.game}}</li>
<li>news003</li>
</ul>
</div>
</template>

# 2.2 命名路由

router/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
path: '/hello',
component: Hello,
children: [
{
name:"news",
path: 'news',
component:News,
},
{
name:"massages",
path: "massages",
component:Messages
}
]
}

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<router-link 
class="list-group-item"
active-class="active"
:to="{
name:'news',
query:{
id:Massages.title,
game:Massages.game
}
}">News</router-link>
<router-link
class="list-group-item"
active-class="active"
:to="{name:'massages'}">massages</router-link>

# 2.3 params

router/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
path: '/hello',
component: Hello,
children: [
{
name:"news",
path: 'news/:title/:id',
component:News,
},
{
name:"massages",
path: "massages",
component:Messages
}
]
}

父组件有两种写法

1
2
3
4
5
6
7
8
//第一种写法
<router-link class="list-group-item" active-class="active" :to="{
name:'news',
params:{
id:Massages.title,
game:Massages.game
}
}">News</router-link>

注意,如果使用了 params 且用上面这种写法,则必须要用 name 来指向

1
2
3
4
5
//第二种写法
<router-link class="list-group-item" active-class="active"
:to="{
/hello/news/666/sabi
">News</router-link>

子组件

1
2
3
4
5
6
7
8
9
10
<template>
<div>
<ul>
<li>{{$route.params.id}}</li>
<li>{{$route.params.game}}</li>
<li>news003</li>
</ul>
</div>
</template>

# 2.4 props

props 的作用主要体现在更方便的传递数据

关于 props 的调用使用方式有三种

第一种

1
2
3
4
5
6
{
name:"news",
path: 'news/:title/:id',
component: News,
props: { id:'1',title:'adwsx'}//直接进行传值
},

1
2
3
4
5
6
7
8
9
<li>{{id}}</li>
<li>{{title}}</li>

<script>
export default {
name:"News",
props:['id','title']
}
</script>

第二种

1
2
3
4
5
6
{
name:"news",
path: 'news/:title/:id',
component: News,
props: true //设定为true以后所有的prams值将都可以通过props传递
},

第三种

1
2
3
4
5
6
7
8
9
10
11
{
name:"news",
path: 'news',
component: News,
props($route) { //以此法可以把所有的query的值传入
return {
id: $route.query.id,
title:$route.query.title,
}
}
},

# 3.replace 属性与函数式路由

# 3.1 replace

router-link 标签默认是 push 模式,即点击一个新的路由组件就历史记录入栈

而更改为 replace 模式后,此组件会替换掉原本栈顶的元素,成为新的栈顶

开启方式

1
<router-link replace class="list":to="{name:'massages'}">massages</router-link>

# 3.2 编程式路由

主要用于希望将路由跳转事件绑定在 a 标签以外的元素上时

1
2
3
4
5
6
7
this.$router.push({
name:"massages",
params:{
id:xxx,
title:xxx
}
})

↑相当于默认标签

1
2
3
4
5
6
7
this.$router.replace({
name:"massages",
params:{
id:xxx,
title:xxx
}
})

↑相当于开始 replace 模式的标签

this.$router.forward () 前进

this.$router.back () 倒退

this.$router.go (3) 前进三步 如果是负数则倒退

# 3.3 缓存路由组件

​ 作用:因为路由组件每次被调用与调走都会重新挂载和销毁组件,但有些数据需要保存,所以需要调用缓存路由组件以保留数据

<keep-alive><keep-alive/> 用这个组件包裹 router-view 标签,会使其中的所有 router 组件避免被销毁

如果需要对特定的组件进行保留,则需要对 include 值进行赋值

1
<keep-alive include="News"><keep-alive/>

# 3.4 新的生命周期

​ 既然有缓存路由组件,那么又有新的问题产生了:如果有设定在组件销毁同时销毁的事件在缓存路由组件中,那他将一直运行下去,这时候我们应该如何处理呢?

activated (){} 组件被选中时调用

deactivated (){} 组件非选中状态销毁

可以理解为活跃和不活跃状态

# 4. 路由守卫

# 4.1 全局守卫

4.1.1 路由前置守卫

​ 这是全局所有组件通用的路由守卫,即所有路由组件调用前都需要经过这一个函数,主要用于进入组件前的权限检验

​ 同时在需要对一大批组件进行检验的时候,我们可以赋一个布尔值给每个组件以用于检验,此时我们并不能直接给组件某一个值赋值,而是用 meta 属性来储存这些值便于调用

1
2
3
4
5
{
path: '/about',
component: About,
meta:{isAuth:false}
},

1
2
3
4
5
6
7
8
9
10
11
12
router.beforeEach((to,from,next) => {
if (to.meta.isAuth) {
if (localStorage.getItem('school') != 'zhouyi') {
alert('你不是学校的,不允许进入')
} else {
next()
}
}
else {
next()
}
})

4.1.2 路由后置守卫

路由后置守卫用的并不多,但有一个功能使用的比较多,即标签页名与跳转的路由名一致。

1
2
3
4
5
6
7
router.afterEach((to, from) => {
if (to.meta.title) {
document.title = to.meta.title;
} else {
document.title='router-test'
}
})

# 4.2 独享守卫

此守卫直接加在路由 js 文件的路由组件部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
name:"news",
path: 'news',
component: News,
meta:{isAuth:true,title:'新闻'},
props($route) {
return {
id: $route.query.id,
title:$route.query.title,
}
},
beforeEnter: (to, from, next) => {
if (to.meta.isAuth) {
if (localStorage.getItem('school') != 'zhouyi') {
alert('你不是学校的,不允许进入')
} else {
next()
}
}
else {
next()
}
}
},

# 4.3 组件路由

顾名思义,在组件内使用的路由,用法与全局路由一直但函数名不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    beforeRouteEnter(to,from,next){
if (to.meta.isAuth) {
if (localStorage.getItem('school') != 'zhouyi') {
alert('你不是学校的,不允许进入')
} else {
next()
}
}
else {
next()
}
},

afterRouteEnter(to, from){
if (to.meta.title) {
document.title = to.meta.title;
} else {
document.title='router-test'
}
}

# 5. 一些注意事项

在没有进行配置过时,重复点击同一个路由按钮会报错,这时候我们需要在 router 配置中加上

1
2
3
4
5
Vue.use(Router)
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to) {
return VueRouterPush.call(this, to).catch(err => err)
}