路由(vue-router)
路由的安装和配置-路由的基本使用-路由导航
# 路由的概念与原理
概念:Hash地址(path)与 组件(component) 之间的对应关系(不同地址,展示不同页面;不同页面显示不同地址)
前端路由的工作方式:
(1)用户点击页面上不同的路由链接,会导致 URL 地址栏中 的 Hash 值发生变化
(2)前端路由监听到 Hash 地址的变化,会把当前 Hash 地址对应的组件 渲染到浏览器中
前端路由底层实现原理:监听 浏览器的 onhashchange 事件(当 Hash 值发生改变时触发这个事件)
手动模拟前端路由
hash 值:URL 的锚部分 (以 '#' 号为开始),如:http://xxx.com/#/home,其中 #/home 就是哈希值
onhashchange 事件:当 哈希值 发生改变时触发
通过设置Location 对象 (opens new window) 的 location.hash (opens new window) 或 location.href (opens new window) 修改/获取 hash 值
<template>
<div class="app-conuainer">
<h1>App 根组件</h1>
<!-- 1. 点击页面上不同的路由链接,URL地址栏中的 Hash 值会发生变化 -->
<a href="#/home">首页</a>
<a href="#/movie">电影</a>
<a href="#/about">关于</a>
<!-- 2. 使用动态组件,按需展示相应的组件(默认展示 Home 组件) -->
<components :is="comName"></components>
<!-- 3. 监听到 Hash 值的变化,就让当前 Hash 地址对应的组件 展示出来 -->
</div>
</template>
<script>
import Home from "@/components/Home.vue"
import Movie from "@/components/Movie.vue"
import About from "@/components/About.vue"
export default {
name: "App", // 给当前组件取个名称
data() {
return {
// 在动态组件的位置,要展示的组件名字,值必须是字符串
comName: "Home"
}
},
// 3. 监听 hash 值的变化(实际开发中不需要自己写路由,vue会帮我们自动创建路由)
// 生命周期函数(组件已经创建)
created() {
// 只要当前 APP 组件一被创建,就立即监听 window 对象的 onhashchange 事件
// onhashchange 事件:当 Hash 值发生改变时触发
window.onhashchange = () => {
console.log("监听到了 hash 地址的变化", location.hash)
// 使用 switch 分支语句,来匹配 Hash 值,谁匹配执行谁
switch (location.hash) {
case "#/home":
this.comName = "Home"
break
case "#/movie":
this.comName = "Movie"
break
case "#/about":
this.comName = "About"
break
}
}
}
// 注册组件
components: {
Home,
Movie,
About
}
}
</script>
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
53
54
55
56
57
58
59
# 1. vue-router 安装和配置
注意:在 vue-cli 创建项目的时候,如果勾选了 vue-router,那么 webpack 会自动帮我们安装并配置路由
(1). 安装 vue-router 包:npm i vue-router@3.5.2 -S
(2). 创建路由模块:在 src 源代码目录下,新建 router/index.js 路由模块,并初始化如下的代码:
// src/router/index.js 就是当前项目的路由模块
// 1.导入 Vue 和 VueRouter 包
import Vue from "vue"
import VueRouter from "vue-router"
// 2. 调用 Vue.use() 函数,把 VueRouter 安装为 Vue 的插件【Vue.use()函数,用于给项目安装插件】
Vue.use(VueRouter)
// 3. 创建路由的实例对象
const router = new VueRouter()
// 4. 向外共享路由的实例对象
export default router
2
3
4
5
6
7
8
9
10
11
12
13
14
(3). 在 main.js 入口文件中,导入并挂载路由模块
// main.js 入口文件
import router from "@/router"
new Vue({
render: h => h(App),
router // 挂载路由
}).$mount('#app')
2
3
4
5
6
7
8
# 2. Vue-router 的基本使用
注意
(1). 设置路由链接:<router-link to="/about"></router-link>
(2). 声明 <router-view></router-view> 来给相应的组件预留位置
(3). 在路由模块(src/router/index.js)中,导入并配置需要展示的组件(把相应的组件展示到预留的位置)

<template>
<div id="app">
<!-- 1. 设置路由链接:使用 router-link 来代替 a 标签 -->
<router-link to="/about">关于</router-link>
<!-- router-view 是一个占位符,作用:把 "路由链接" 对应的 "组件" 展示到这个位置 -->
<router-view></router-view>
</div>
</template>
2
3
4
5
6
7
8
9
// src/router/index.js
// 1. 导入需要的组件
import About from "@/components/About.vue"
// 创建路由的实例对象
const router = new VueRouter({
// 2. routes 是一个数组,作用:定义 "hash 地址" 与 "组件" 之间的对应关系
routes: [
// 路由规则:path 是路由链接, component 是对应的组件
{ path: "/about", component: About },
]
})
2
3
4
5
6
7
8
9
10
11
12
13
# 3. 动态路由匹配
动态路由
(1). 把 Hash 地址中可变的部分,做为动态的参数项
(2). 在 vue-router 中使用英文的冒号(:参数项名称)来定义路由的参数项,参数项名称可自定义
(3). 动态路由,可以提高路由规则的复用性

/*
动态路由匹配:将 路由地址(Hash地址)中,可变的部分做为"参数项"
使冒号 :参数项名称 来表示动态的参数项,参数项名字自定义
把某种模式匹配到的所有路由,都映射到同个组件(如:/about/1、/about/2等,都映射到相同的路由)
获取动态参数的两种方法:
1. this.$route.params.id(this可以省略)
2. index.js路由模块中开启props传参,组件中使用 props 来接收
*/
// 这里有3个路由链接,必须要写3条路由规则吗?
// 答案:no,动态路由可以把多条路由规则合并成一个规则,提高路由规则的复用性
<router-link to="/about/1">关于1</router-link>
<router-link to="/about/2">关于2</router-link>
<!-- 在Hash地址中, / 后面的参数项,叫做"路径参数", ?号后面的参数向叫做"查询参数" -->
<router-link to="/about/3?name=zs age=20">关于3</router-link>
<script>
export default {
methods: {
showThis() {
console.log(this);
console.log("路由的参数对象:",this.$route);
console.log("在路由的参数对象中,path是部分路径,fullPath是完整地址,queyr是查询参数");
console.log("路由的导航对象:",this.$router);
}
},
// 用于接收动态参数值
props: ["id"]
};
</script>
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
// index.js 就是当前项目的路由模块
// { path: "/movie/1", component: Movie }
// { path: "/movie/2", component: Movie }
// { path: "/movie/3", component: Movie }
// 动态路由:可以提高路由规则的复用性(将以上3条路由规则,合并成一条)
{ path: "/about/:id", component: About, props: true }
// :id 表示动态的参数项:把路由链接可变的部分做为动态的参数项,参数项名称可自定义
// props:true 表示开启props传参,让父组件可以接收到动态参数值
2
3
4
5
6
7
8
9
10
# 4. 嵌套路由
嵌套路由:路由里面嵌套路由(子路由规则),使用 children 属性声明子路由规则
<template>
<div class="movie-conuainer">
<h3>Movie 组件</h3>
<!-- 1. 设置子路由链接 -->
<!-- <router-link to="/movie">动作片</router-link> 默认子路由的链接 -->
<router-link to="/movie/tab1">动作片</router-link>
<router-link to="/movie/tab2">爱情片</router-link>
<router-link to="/movie/tab3">喜剧片</router-link>
<!-- 2. 把 "路由链接" 对应的 "组件" 展示到这个位置 -->
<router-view></router-view>
<!-- 3. 在 src/router/index.js 路由模块中,导入需要的组件,并配置子路由规则 -->
</div>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 导入组件(用于给 Movie 组件配置子路由)
import Tab1 from "@/components/tabs/tab1.vue"
import Tab2 from "@/components/tabs/tab2.vue"
import Tab3 from "@/components/tabs/tab3.vue"
// 创建路由的实例对象
const router = new VueRouter({
routes: [
// 重定向路由规则:访问域名,默认展示首页组件
{ path: "/", redirect: "/home" },
// 路由规则:path 是路由链接, component 是对应的组件
{ path: "/home", component: Home },
{ path: "/movie", component: Movie },
// 嵌套路由:路由里面嵌套路由
{ path: "/about", component: About,
// 使用 children 属性,为 about 路由,添加3条子路由规则
children: [
{ path: "tab1", component: Tab1 },
{ path: "tab2", component: Tab2 },
{ path: "tab3", component: Tab3 },
// 默认子路由:path 的值为空,相当于路由重定向(默认展示Tab1组件)
// { path: "", component: Tab1 }
],
// 重定向的子路由规则,访问 xxx.com/movie 则是 xxx.com/movie/tab1
redirect: "/movie/tab1"
}
]
})
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
# 5. 编程式导航
声明式导航:通过点击链接实现导航的方式,叫做声明式导航
编程式导航:通过调用 API 方法跳转到新页面的方式,属于编程式导航
/*
声明式导航:通过点击链接实现导航的方式,叫做声明式导航
编程式导航:通过调用 API 方法跳转到新页面的方式,属于编程式导航
vue-router 提供了许多编程式导航的 API,其中最常见的导航 API 如下:
1. this.$router.push("Hash地址")
跳转到指定 hash 地址,并增加一条历史记录(浏览器中会留下历史记录)
2. this.$router.replace("Hash地址")
跳转到指定 hash 地址,并替换掉当前的历史记录
3. this.$router.go(n)
可以在浏览历史中前进和后退,前进/后退到之前的浏览页面
n 表示数值(正数/负数):1 表示前进;-1 表示后退
4. 前进/后退另一种写法
前进:this.$router.forward()
后退:this.$router.back()
以上 API 方法,可以写到 methods 方法里面(需加this),也可以直接写在行内中(不加this)
*/
<!-- 1. 声明式导航:通过点击链接,实现页面切换 -->
<a href="#/movie/tab1">电影1</a>
<router-link to="/movie/tab2">电影2</router-link>
<!-- 2. 编程式导航:通过 调用 API 方法,实现跳转页面-->
<button @click='$router.push("/movie/tab1")'>通过 push 跳转到"movie/tab1"页面</button>
<button @click='$router.replace("/movie/tab2")'>通过 replace 跳转到"movie/tab2"页面</button>
<button @click="$router.go(1)">前进</button>
<button @click="$router.go(-1)">后退</button>
<!-- 前进/后退另一种写法 -->
<button @click="$router.forward()">forward 前进</button>
<button @click="$router.back()">back 后退</button>
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
# 6. 路由导航守卫
导航守卫:用于控制路由的访问权限,用户是否有权限从A页面跳转到B页面(如:未登录情况下,不能直接访问到后台)

前置导航守卫(全局)
(1). 定义全局守卫:在 index.js 路由模块中声明
(2). 在每次发生路由的导航跳转时,都会触发全局前置守卫
(3). 在全局前置守卫中,程序员可以对每个路由进行访问权限的控制

// Home 组件
// 如:用户点击路由链接,希望前往后台页面
<router-link to="/main">后台页面</router-link>
2
3
4
// src/router/index.js 当前项目的路由模块
// 1.导入 Vue 和 VueRouter 包
import Vue from "vue"
import VueRouter from "vue-router"
// 2. 调用 Vue.use() 函数,把 VueRouter 安装为 Vue 的插件【Vue.use()函数,用于给项目安装插件】
Vue.use(VueRouter)
// 3. 创建路由的实例对象
const router = new VueRouter()
// 为 router 实例对象,声明全局前置导航守卫
// 只要发生了路由的跳转,都会触发 beforEach 指定的 function 回调函数
router.beforEach(function(to, from, next){
// to 是 当前所处页面 的 路由信息对象
console.log(to)
// from 是 前一个页面的路由信息对象(来自哪里)
console.log(from)
// next 是一个函数,用于控制用户的访问权限(next函数有三种调用方式如下)
next() // 表示放行,允许用户访问任何页面
next("/login") // 表示没有访问权限,强制其跳转到登录页面
next(false) // 表示没有访问权限,强制其停留在当前所处页面
})
// 4. 向外共享路由的实例对象
export default router
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
# 7. 设置页面标题(额外小知识)
当路由链接发生改变时(切换页面时),让浏览器显示相应页面的title
- 在路由规则中添加 meta 属性:meta: { title: "首页" }
// src/router/index.js 路由模块
// 路由规则
{ path: "/", component: Home, meta: { title: "首页" } }, // meta 用于给页面添加 title
{ path: "/about", component: About, meta: { title: "关于" } }
2
3
4
5
- 在 main.js 入口文件中,添加
// main.js 入口文件
router.afterEach((to, from, next) => {
// 切换页面时,滚动到顶部
window.scrollTo(0,0)
/* 路由发生变化修改页面title */
if (to.meta.title) {
document.title = to.meta.title
}
})
2
3
4
5
6
7
8
9
10
# 8. 路由传参(实现页面跳转)
参考:路由传参(实现页面跳转)