19-路由
码路教育 6/3/2022
# 1, 认识前端路由
# 1.1, 前端路由介绍
路由其实是网络工程中的一个术语
- 在架构一个网络时,非常重要的两个设备就是路由器和交换机
- 目前在我们生活中路由器也是越来越被大家所熟知,因为我们生活中都会用到路由器
- 路由器主要维护的是一个映射表,映射表会决定数据的流向
前端路由的实现方案(前端路由是如何做到URL和内容进行映射呢?监听URL的改变)
- 前端路由的核心是什么呢?改变URL,但是页面不进行整体的刷新
- URL的hash
- HTML5的History
URL的hash
- URL的hash也就是锚点(#), 本质上是改变window.location的href属性
- 我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新
- hash的优势就是兼容性更好,在老版IE中都可以运行,但是缺陷是有一个#,显得不像一个真实的路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<a href="#/home">home</a>
<a href="#/about">about</a>
<div class="router-view"></div>
</div>
<script>
// 1,获取router-view
const routerViewEl = document.querySelector(".router-view");
// 2, 监听hashchange
window.addEventListener("hashchange", () => {
switch (location.hash) {
case "#/home":
routerViewEl.innerHTML = "home";
break;
case "#/about":
routerViewEl.innerHTML = "about";
break;
default:
routerViewEl.innerHTML = "default";
}
})
</script>
</body>
</html>
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
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
HTML5的History(history接口是HTML5新增的, 它有六种模式改变URL而不刷新页面)
- replaceState:替换原来的路径
- pushState:使用新的路径
- popState:路径的回退
- go:向前或向后改变路径
- forward:向前改变路径
- back:向后改变路径
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<style>
* {
/* global font */
font-family: Verdana;
font-size: 18px;
}
#root {
display: flex;
flex-direction: row;
}
#content {
display: flex;
display: block;
width: 800px;
height: 250px;
/* vertically centered text */
line-height: 250px;
border: 2px solid #555;
margin: 32px;
text-align: center;
}
.route {
cursor: pointer;
justify-content: center;
width: 150px;
height: 50px;
/* vertically centered text */
line-height: 50px;
position: relative;
border: 2px solid #555;
background: white;
text-align: center;
margin: 16px;
}
.route.selected {
background: yellow;
}
</style>
<body>
<section id="root">
<section class="route" id="home">/home</section>
<section class="route" id="about">/about</section>
<section class="route" id="gallery">/gallery</section>
<section class="route" id="contact">/contact</section>
<section class="route" id="help">/help</section>
</section>
<main id="content">Content loading...</main>
</body>
<script type="text/javascript">
window.onload = event => {
//监听 路由的点击事件 执行push方法
window["home"].addEventListener("click", event => push(event))
window["about"].addEventListener("click", event => push(event))
window["gallery"].addEventListener("click", event => push(event))
window["contact"].addEventListener("click", event => push(event))
window["help"].addEventListener("click", event => push(event))
}
function select_tab(id) {
// 改变 路由按钮的样式
document.querySelectorAll(".route").forEach(item => item.classList.remove('selected'));
document.querySelectorAll("#" + id).forEach(item => item.classList.add('selected'));
}
function load_content(id) {
//更新内容
document.querySelector("#content").innerHTML = 'Content loading for /' + id + '...';
}
function push(event) {
let id = event.target.id;
select_tab(id);
document.title = id;
load_content(id);
window.history.pushState({
id
}, `${id}`, `/page/${id}`);
}
window.addEventListener("popstate", event => {
let stateId = event.state.id;
select_tab(stateId);
load_content(stateId);
});
</script>
</html>
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 2, 认识vue-router
# 2.1, vue-router介绍
目前前端流行的三大框架, 都有自己的路由实现
- Angular的ngRouter
- React的ReactRouter
- Vue的vue-router
Vue Router 是 Vue.js 的官方路由
- 它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用(SPA)变得非常容易
- 路由用于设定访问路径, 将路径和组件映射起来
- 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换
- 安装Vue Router:npm install vue-router@3.5.3
路由的使用步骤
- 第一步:创建路由需要映射的组件(打算显示的页面)
- 第二步:通过new VueRouter创建路由对象,并且传入routes和history模式
- 安装插件 Vue.use(VueRouter);
- 配置路由映射: 组件和路径映射关系的routes数组
- 创建基于hash或者history的模式
- 第三步:通过 router 配置参数注入路由,从而让整个应用都有路由功能
- 第四步:路由使用: 通过router-link和router-view
// router/index.js
//配置路由
//引入vue-router插件:经过打印查看,引入进来的VueRouter构造函数
//vue基础学习构造函数:Vue、VueComponent、Vuex.Store、VueRouter
import VueRouter from 'vue-router';
import Vue from 'vue';
//安装插件
Vue.use(VueRouter);
//引入路由组件
import Home from '../pages/Home';
import About from '../pages/About';
//配置项目的路由
//通过VueRouter【路由器】类,创建了一个VueRouter类的一个实例!!!
//对外暴露
export default new VueRouter({
mode: 'history',
routes: [{
// path配置的是根路径: /
path: "/",
// redirect是重定向, 也就是我们将根路径重定向到/home的路径下, 这样就可以得到我们想要的结果了
redirect: "/home"
}, {
//path设置路由的K,path有的属性值务必都是小写的
path: "/home",
//component设置路由的V,一个K对应一个V
component: Home,
}, {
path: '/about',
component: About
},
]
});
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
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
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from "./routes/router"
// 把路由对象挂载到根实例上
// 那么它的子子孙孙都可以使用这个路由对象
new Vue({
router,
render: h => h(App),
}).$mount('#app')
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
// Home.vue
<template>
<div>
<h1>Home组件</h1>
</div>
</template>
<script>
export default {
name: "Home",
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// About.vue
<template>
<div>
<h1>About组件</h1>
</div>
</template>
<script>
export default {
name:"About"
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// App.vue
<template>
<div id="app">
<!-- router-link 当成a标签 -->
<router-link to="/home" active-class="active">Home</router-link>
<router-link to="/about" active-class="active">About</router-link>
<hr>
<!-- 路由的出口:路由匹配到的组件,需要放到路由出口 -->
<router-view />
</div>
</template>
<script>
export default {
name: "App",
};
</script>
<style lang="less">
.active{
color: red;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 3, router-link
# 3.1, router-link属性
router-link属性
- to属性: 是一个字符串,或者是一个对象
- replace属性:设置 replace 属性的话,当点击时,会调用 router.replace(),而不是 router.push();
- active-class属性:设置激活a元素后应用的class,默认是router-link-active
- exact属性:精确匹配模式
# 4, 路由懒加载
# 4.1, 路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载:
- 如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效
- 也可以提高首屏的渲染效率
- Vue Router默认就支持动态来导入组件
- 因为component可以传入一个组件,也可以接收一个函数,该函数需要放回一个Promise,而import函数就是返回一个Promise
- 分包是没有一个很明确的名称的,其实webpack从3.x开始支持对分包进行命名(chunk name)
{
path: "/",
redirect: "/home"
}, {
path: "/home",
component: ()=>import(/* webpackChunkName: "home" */"../pages/Home.vue"),
}, {
path: '/about',
component: ()=>import(/* webpackChunkName: "about" */"../pages/About.vue"),
},
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
打包后的代码如下:
# 5, 路由其他属性
# 5.1, 路由其他属性
- name属性:路由记录独一无二的名称;
- meta属性:自定义的数据
{
path: "/",
redirect: "/home"
}, {
path: "/home",
component: ()=>import(/* webpackChunkName: "home" */"../pages/Home.vue"),
name:"home"
}, {
path: '/about',
component: ()=>import(/* webpackChunkName: "about" */"../pages/About.vue"),
name:"about",
meta:{
name:"wc",
age:18
}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 6, 嵌套路由和404组件
# 6.1, 嵌套路由
什么是路由的嵌套呢?
- 我们匹配的Home、About等都属于第一级路由,我们在它们之间可以来回进行切换
- Home页面本身,也可能会在多个组件之间来回切换
- 比如Home中包括Cart、Mine,它们可以在Home内部来回切换
- 这个时候我们就需要使用嵌套路由,在Home中也使用 router-view 来占位之后需要渲染的组件
404组件
- 对于哪些没有匹配到的路由,我们通常会匹配到固定的某个页面
- 在路由规则最后面配置:{ path:"*", component:NotFount },
import Vue from "vue";
import VueRouter from "vue-router"
// 自定义的组件 直接引入 下面的组件,一上来,就全部引入
import Home from "../components/Home"
// import About from "../components/About"
import NotFount from "../components/NotFount"
import Cart from "../components/Cart"
// import Mine from "../components/Mine"
// 能不能点击某个连接时,用到了这个组件,再去引入呢?
// 答:可以,使用路由的懒加载
Vue.use(VueRouter);
// 配置路由规则
let routes = [
{ path:"/", redirect:"/home" },
{
path:"/home",
component:Home,
children:[
{ path:"/home", redirect:"/home/cart" },
{ path:"/home/cart", component:Cart },
{ path:"/home/mine", component:()=>import(/* webpackChunkName: "Mine" */"../components/Mine") },
]
},
// { path:"/about", component:About },
{ path:"/about", component:()=>import(/* webpackChunkName: "About" */"../components/About") },
{ path:"*", component:NotFount },
];
let router = new VueRouter({
// hash路由有一个特点,就是#
mode:"hash", // hash路由
routes
})
export default router;
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
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
// Home.vue
<template>
<div>
<h1>Home组件</h1>
<router-link to="/home/cart">购物车</router-link>
<router-link to="/home/mine">我的</router-link>
<hr>
<router-view />
</div>
</template>
<script>
export default {
name: "Home",
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// About.vue
<template>
<div>
<h1>About组件</h1>
</div>
</template>
<script>
export default {
name:"About"
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Cart.vue
<template>
<div>
<h3>购物车</h3>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Mine.vue
<template>
<div>
<h3>我的</h3>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// NotFount.vue
<template>
<div>
<h3>你的页面飞了</h3>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// App.vue
<template>
<div id="app">
<!-- router-link 当成a标签 -->
<router-link to="/home" active-class="active">Home</router-link>
<router-link to="/about" active-class="active">About</router-link>
<hr>
<!-- 路由的出口:路由匹配到的组件,需要放到路由出口 -->
<router-view />
</div>
</template>
<script>
export default {
name: "App",
data(){
return{
}
},
methods:{
},
components: {
},
};
</script>
<style lang="less">
.active{
color: red;
}
</style>
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
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
# 7, 动态路由
# 7.1, 动态路由基本匹配
很多时候我们需要将给定匹配模式的路由映射到同一个组件
- 例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但是用户的ID是不同的;
- 在Vue Router中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数;
获取动态路由的值
- 在template中,直接通过 $route.params获取值
- 在created中,通过 this.$route.params获取值
import VueRouter from "vue-router";
import Vue from "vue";
import Home from "../components/Home"
import About from "../components/About"
import Mine from "../components/Mine"
import NotFount from "../components/NotFount"
Vue.use(VueRouter);
let routes = [
{ path:"/", redirect:"/home" },
{ path:"/home", component:Home },
{ path:"/about", component:About },
{ path:"/mine/:name/:age/:address", component:Mine },
{ path:"*", component:NotFount },
];
let router = new VueRouter({
// hash带#
// history不带#
mode:"history",
routes
})
export default router;
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
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
// Home.vue
<template>
<div>
<h2>Home</h2>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// About.vue
<template>
<div>
<h2>About</h2>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Mine.vue
<template>
<div>
<h2>Mine -- {{ name }}</h2>
<h2>Mine -- {{ age }}</h2>
<h2>Mine -- {{ address }}</h2>
</div>
</template>
<script>
export default {
// 需要获取动态路由参数
// 使用路由,需要知道4个知识点
// 1)<router-view /> 路由出口
// 2)<router-link /> a标签 点击跳转
// 3)$router 对象 有一堆的方法 挂载到当前组件实例上 this
// 3)$route 对象 有一堆的属性 挂载到当前组件实例上 this
data(){
return{
name:"",
age:"",
address:"",
}
},
// 生命周期函数(钩子函数)
created(){
// 获取动态路由参数
console.log(this.$route);
console.log(this.$route.params.name);
this.name = this.$route.params.name
this.age = this.$route.params.age
this.address = this.$route.params.address
}
}
</script>
<style>
</style>
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
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
// NotFount.vue
<template>
<div>
<h2>404</h2>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// App.vue
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: "App",
data(){
return{
}
},
methods:{
},
components: {
},
};
</script>
<style lang="less">
.active{
color: red;
}
</style>
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
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
在router-link中进行如下跳转:
<router-link to="/main/wc/18/bj">我的</router-link>
1
# 8, 编程式路由(代码的页面跳转)
# 8.1, 代码的页面跳转
有时候我们希望通过代码来完成页面的跳转,比如点击的是一个按钮
- 此时,我们可以使用编程式路由
- this.$router.push("/about")
- 当然,我们也可以传入一个对象
- this.$router.push({path:"/about"})
- this.$router.push({name:"about"})
query方式的参数
- this.$router.push({path:"/about",query:{name:"wc",age:18}})
- 在界面中通过 $route.query 来获取参数
query: -
params方式的参数
- this.$router.push({path:"/about",params:{ address:"bj" }})
- 在界面中通过 $route.params 来获取参数
页面的前进后退
- router的go方法:
- router.go(1) 向前移动一条记录,与router.forword()相同
- router.go(-1) 向后移动一条记录,与router.back()相同
- router.go(3) 前进3条记录
- router.go(100) 如果没有那么多记录,静默失败
- router.go(-100) 如果没有那么多记录,静默失败
- router也有back:
- 通过调用 history.back() 回溯历史。相当于 router.go(-1)
- router也有forward:
- 通过调用 history.forward() 在历史中前进。相当于 router.go(1)
import VueRouter from "vue-router";
import Vue from "vue";
import Home from "../components/Home"
import About from "../components/About"
import Mine from "../components/Mine"
import NotFount from "../components/NotFount"
Vue.use(VueRouter);
let routes = [
{ path:"/", redirect:"/home" },
{ path:"/home", name:"home", component:Home },
{ path:"/about", name:"about", component:About },
{ path:"/mine", name:"mine", component:Mine },
{ path:"*", component:NotFount },
];
let router = new VueRouter({
// hash带#
// history不带#
mode:"history",
routes
})
export default router;
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
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
// Home.vue
<template>
<div>
<h2>Home</h2>
<button @click="toAbout">去about</button>
<button @click="forward">forward</button>
</div>
</template>
<script>
export default {
methods: {
toAbout() {
// 实现跳转到about
// this上有route 还有router
// route上有一堆的属性
// router上有一堆方法
// 跳转方式一:
// this.$router.push("/about")
// 跳转方式二:
// this.$router.push({ path:"/about" })
// 跳转方式三:
// this.$router.push({ name:"about" })
// 跳转传参方式一:
// this.$router.push({ name:"about", params:{ address:"bj" } })
// 跳转传参方式二:
this.$router.push({ name:"about", query:{ score:"100分" } })
// replace
// this.$router.replace({ name:"about", query:{ score:"100分" } })
},
forward(){
// this.$router.forward()
this.$router.go(1) // go(1) 等价于 forward
}
},
};
</script>
<style>
</style>
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
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
// About.vue
<template>
<div>
<h2>About</h2>
<!-- <p>{{ $route.params.address }}</p> -->
<p>{{ $route.query.score }}</p>
<button @click="back">back</button>
</div>
</template>
<script>
export default {
// 4个东西:两个组件 两个对象route rotuer
created(){
console.log(this.$route);
// console.log(this.$route.params.address);
console.log(this.$route.query.score);
},
methods:{
back(){
// this.$router.back();
this.$router.go(-1); // go(-1) 等价于 back
}
}
}
</script>
<style>
</style>
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
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
// Mine.vue
<template>
<div>
<h2>Mine</h2>
</div>
</template>
<script>
export default {
data(){
return{
}
},
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// NotFount.vue
<template>
<div>
<h2>404</h2>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// App.vue
<template>
<div id="app">
<router-link to="/home" active-class="active">home</router-link>
<router-link to="/about" active-class="active">about</router-link>
<router-link to="/mine" active-class="active">mine</router-link>
<hr>
<router-view />
</div>
</template>
<script>
export default {
name: "App",
data(){
return{
}
},
methods:{
},
components: {
},
};
</script>
<style lang="less">
.active{
color: red;
}
</style>
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
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
# 9, 路由导航守卫
# 9.1, 路由导航守卫
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航
全局的前置守卫beforeEach是在导航触发时会被回调的:
- to:即将进入的路由Route对象
- from:即将离开的路由Route对象
- next: 在Vue2中我们是通过next函数来决定如何进行跳转的,是在Vue3中我们是通过返回值来控制的,不再推荐使用next函数,这是因为开发中很容易调用多次next;
// /router/index.js
import VueRouter from "vue-router";
import Vue from "vue";
import Home from "../components/Home"
import About from "../components/About"
import Mine from "../components/Mine"
import Login from "../components/Login"
import NotFount from "../components/NotFount"
Vue.use(VueRouter);
let routes = [
{ path:"/", redirect:"/home" },
{ path:"/home", name:"home", component:Home },
{ path:"/about", name:"about", component:About },
{ path:"/mine", name:"mine", component:Mine },
{ path:"/login", name:"login", component:Login },
{ path:"*", component:NotFount },
];
let router = new VueRouter({
// hash带#
// history不带#
mode:"history",
routes
})
// 配置全局路由守卫
// to表示去哪
// from表示从哪里来
// next表示是否放行 放行到哪里
router.beforeEach((to,from,next)=>{
// console.log("from:",from);
// console.log("to:",to);
if(to.path !== "/login"){
// 去的地方不是/login
// 只有登录了,才能去/home /about /mine
if(window.isLogin){
// 表示已登录
next();
}else{
return next("/login");
}
}
next();
});
export default router;
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
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
// Home.vue
<template>
<div>
<h2>Home</h2>
</div>
</template>
<script>
export default {
methods: {
toAbout() {
},
},
};
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// About.vue
<template>
<div>
<h2>About</h2>
</div>
</template>
<script>
export default {
methods:{
}
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Mine.vue
<template>
<div>
<h2>Mine</h2>
</div>
</template>
<script>
export default {
data(){
return{
}
},
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Login.vue
<template>
<div>
<button @click="login">登录</button>
</div>
</template>
<script>
export default {
methods:{
login(){
// 给GO上放一个isLogin是true
window.isLogin = true;
}
}
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// NotFount.vue
<template>
<div>
<h2>404</h2>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// App.vue
<template>
<div id="app">
<router-link to="/home" active-class="active">home</router-link>
<router-link to="/about" active-class="active">about</router-link>
<router-link to="/mine" active-class="active">mine</router-link>
<hr>
<router-view />
</div>
</template>
<script>
export default {
name: "App",
data(){
return{
}
},
methods:{
},
components: {
},
};
</script>
<style lang="less">
.active{
color: red;
}
</style>
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
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
其他导航守卫:
- Vue还提供了很多的其他守卫函数,目的都是在某一个时刻给予我们回调,让我们可以更好的控制程序的流程或者功能
- https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html
完整的导航解析流程:
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫(2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。