一、介绍
route【路由】
- 是一组 key-value 的映射关系
- 前端路由和后端路由
- 前端路由的作用:根据路径,局部刷新页面的内容
- 后端路由的作用:根据请求路径,找到匹配的方法进行对应的处理并给出响应
router【路由器】
- 管理多组路由规则
vue-router
- vue 的一个插件库,专门用来实现 SPA 应用,实时监控路由的变化
对 SPA 应用的理解
- 单页 Web 应用(single page web application,SPA)
- 整个应用只有一个完整的页面
- 点击页面中的导航链接不会刷新页面,只会做页面的局部更新
- 数据需要通过 ajax 请求获取
二、路由的简单使用
1. 简单使用
安装
vue-router
插件
npm i vue-router@3
编写路由配置文件:
src/router/index.js
import Vue from 'vue';
import VueRouter from "vue-router";
import MyAbout from "@/components/MyAbout.vue";
import MyHome from "@/components/MyHome.vue";
// 注册 vue-router 插件
Vue.use(VueRouter)
// 编写并暴露管理路由的规则,自定义的路由器
export default new VueRouter({
routes: [
{
path: '/about',
component: MyAbout,
},{
path: '/home',
component: MyHome,
}
],
})
引入自定义的路由器
import Vue from 'vue';
import App from './App.vue';
// 引入
import router from './router/index'
new Vue({
el: '#app',
// 注册
router,
render: h => h(App)
});
在模板中书写切换路由的代码
<template>
<div>
<router-link to="/about">About</router-link>
<hr>
<router-link to="/home">Home</router-link>
<hr>
<router-view></router-view>
</div>
</template>
2. 注意事项
第一个注意点
组件分类
- 一般组件:自己使用路由标签,一般书写在
src/components
里面 - 路由组件:在路由器里面引入,然后在 router-link 使用,一般书写在
src/pages
里面
第二个注意点
组件如果被切换掉,被路由切换掉,那么被切换的组件会被销毁,可以使用生命周期验证,先销毁旧的,再切换挂载新的组件
第三个注意点
所有的 vm、vc 身上都增加了两个属性:$router
、$route
$route
:每个组件有一个独立的route
$router
:整个项目只有一个router
,路由器只有一个
3. 嵌套路由
嵌套路由、多级路由
一般情况下,最多只用到四五级路由
二级路由以及之后的路由的
path
属性不要以/
开头
export default new VueRouter({
routes: [
{
path: '/about',
component: MyAbout,
},{
path: '/home',
component: MyHome,
children: [
{
path: 'a',
component: MyA,
},{
path: 'b',
component: MyB,
}
]
}
],
})
4. 命名路由
配置路由:尽管通过 name 属性进行路由切换,path 属性依然不可省略
export default new VueRouter({
routes: [
{
name: 'guanyu',
path: '/about',
component: MyAbout,
},{
name: 'zhuye',
path: '/home',
component: MyHome,
}
],
})
直接使用 name 进行路由跳转
<template>
<div>
<router-link :to="{name:'guanyu'}">About</router-link>
<hr>
<router-link :to="{name:'zhuye'}">Home</router-link>
<hr>
<router-view></router-view>
</div>
</template>
三、路由传参
1. query 传参
(1)传递参数
字符串写法:path
<router-link :to="`/about?id=${'002'}&name=${'tom'}&age=${178}`">About</router-link>
对象写法:path、name
<router-link :to="{
path:'/about',
query: {
id: '001',
name: 'tom',
age: 19,
}
}">About</router-link>
<router-link :to="{
name:'guanyu',
query: {
id: '001',
name: 'tom',
age: 19,
}
}">About</router-link>
(2)接收参数
<ul>
<li>{
{ $route.query.id }}</li>
<li>{
{ $route.query.name }}</li>
<li>{
{ $route.query.age }}</li>
</ul>
2. params 传参
(1)先占位置
export default new VueRouter({
routes: [
{
name: 'guanyu',
// 使用 :XXX 来占位置
path: '/about/:id/:name/:age',
component: MyAbout,
},{
name: 'zhuye',
path: '/home',
component: MyHome,
}
],
})
(2)传递参数
字符串传参:必须使用 path 来填充占位符
<router-link to="/about/006/jack/28">About</router-link>
对象传参:必须使用 name,因为 path 已经不可以精准匹配了
<router-link class="nav-title" :to="{
name: 'guanyu',
params: {
id: 'abc',
name: 'mary',
age: 56
}
}">About</router-link>
(3)接收参数
<ul>
<li>{
{ $route.params.id }}</li>
<li>{
{ $route.params.name }}</li>
<li>{
{ $route.params.age }}</li>
</ul>
3. 通过路由的 props 参数传参
让路由组件更方便的接收数据
(1)写法一
配置 porps 属性,将所有的 k-v 数据传递到对应组件的 props 属性中
传递
export default new VueRouter({
routes: [
{
name: 'guanyu',
path: '/about',
component: MyAbout,
// 配置 porps 属性,将该属性所有的 k-v 数据传递到对应组件的 props 属性中
props: {
id: '001',
name: 'jack001',
age: 89
}
}
],
})
接收
<script>
export default {
name: 'MyAbout',
props: ['id', 'name', 'age']
}
</script>
使用
<ul>
<li>{
{ id }}</li>
<li>{
{ name }}</li>
<li>{
{ age }}</li>
</ul>
(2)写法二
配置 porps 属性,将路由收到的所有 params 属性传递到对应组件的 props 属性中【不需要占位符】
传递
<router-link class="nav-title" :to="{
name: 'guanyu',
params: {
id: 'ab5656c',
name: 'mary',
age: 56
}
}">About
</router-link>
开启 props 转换
export default new VueRouter({
routes: [
{
name: 'guanyu',
path: '/about',
component: MyAbout,
// 转换
props: true
}
],
})
接收
<script>
export default {
name: 'MyAbout',
props: ['id', 'name', 'age']
}
</script>
使用
<ul>
<li>{
{ id }}</li>
<li>{
{ name }}</li>
<li>{
{ age }}</li>
</ul>
(3)写法三
手动将 $router 的数据读取出来传递给对应组件的 props 属性上
传递
<router-link class="nav-title" :to="{
name: 'guanyu',
params: {
id: 'abc',
name: 'mary',
age: 56
}
}">About</router-link>
路由处理
export default new VueRouter({
routes: [
{
name: 'guanyu',
path: '/about',
component: MyAbout,
props($route) {
return {
id: $route.params.id,
name: $route.params.name,
age: $route.params.age,
}
}
}
],
})
也可以解构赋值
export default new VueRouter({
routes: [
{
name: 'guanyu',
path: '/about',
component: MyAbout,
props({
params}) {
return {
id: params.id,
name: params.name,
age: params.age,
}
}
}
],
})
四、route-link 的历史记录模式
有两种工作模式
- 【push】压栈模式:可以前进后退页面,route-link 的默认就是压栈模式
- 【replace】替换模式:会干掉当前的记录,不可以前进后退页面
1. 压栈模式
<router-link to="/about">About</router-link>
<!-- OR -->
<router-link push to="/about">About</router-link>
2. 替换模式
<router-link replace to="/about">About</router-link>
五、编程式路由导航
<router-link>
最终会编译成<a>
标签,所以可以在<router-link>
标签上面写类名- 编程式路由使用
router
实现路由跳转,可以不使用<router-link>
实现路由跳转,更灵活
1. 简单使用
<button class="nav-title" @click="toAbout">About</button>
<button class="nav-title" @click="toHome">Home</button>
<script>
export default {
name: 'App',
methods: {
toAbout() {
this.$router.push({
name: 'guanyu',
params: {
id: '0514df',
name: 'dsgfsd ',
age: 59
}
})
},
toHome() {
this.$router.push({
path: '/home'
})
},
}
}
</script>
2. 补充
this.$router.push({
name: 'guanyu',
params: {
id: '0514df',
name: 'dsgfsd ',
age: 59
}
})
this.$router.replace({
name: 'guanyu',
params: {
id: '0514df',
name: 'dsgfsd ',
age: 59
}
})
this.$router.forward() 前进
this.$router.back() 后退
this.$router.go(n) 可前进也可后退,n为正数前进n,为负数后退
this.$router.go(0) 刷新页面
六、缓存路由组件
作用:让不展示的路由组件保持挂载,不被销毁,可以通过钩子函数来验证
使用场景
- 默认情况下,路由跳转使得组件切换,且切换的组件的用户临时输入的数据会消失,路由缓存可以解决该问题
1. 缓存使用的所有组件
<keep-alive>
<router-view></router-view>
</keep-alive>
2. 缓存指定组件
组件名称、组件名称、组件名称
<keep-alive include="MyAbout">
<router-view></router-view>
</keep-alive>
<!-- 注意 `v-bind:` -->
<keep-alive :include=['MyAbout', 'MyHome']>
<router-view></router-view>
</keep-alive>
七、路由组件专属的钩子函数
activated 和 deactivated 是路由组件所独有的两个钩子,用于捕获路由组件的激活状态
* activated 路由组件被激活时触发
* deactivated *路由组件失活时触发
对于被缓存的路由组件,路由切换时不会销毁组件,也就不会执行
destoryed
钩子函数,那么如下的定时器是不会被销毁的
<script>
export default {
name: 'MyAbout',
props: ['id', 'name', 'age'],
mounted() {
console.log('组件被挂载了,绑定了定时器')
this.timer = setInterval(() => {
this.opacity -= 0.01
if (this.opacity <= 0) this.opacity = 1
}, 10)
},
destoryed() {
console.log('组件销毁了,解绑了定时器')
clearInterval(this.timer)
}
}
</script>
使用 activated、deactivated 即可解决问题
<script>
export default {
name: 'MyAbout',
props: ['id', 'name', 'age'],
activated() {
console.log('组件被激活了,绑定了定时器')
this.timer = setInterval(() => {
this.opacity -= 0.01
if (this.opacity <= 0) this.opacity = 1
}, 10)
},
deactivated() {
console.log('组件失活了,解绑了定时器')
clearInterval(this.timer)
}
}
</script>
八、history 和 hash
路由器的两种工作模式
- hash模式
- history模式
路径的哈希值:# 之后的参数,其中哈希值不包含在 HTTP 请求中,也即不会将这些参数发送到服务器
export default new VueRouter({
mode: 'history',
routes: [
......
],
})
// OR
export default new VueRouter({
mode: 'hash',
routes: [
......
],
})
九、路由守卫
如果使用了路由守卫,路由配置文件就需要改成下面的格式
import Vue from 'vue'; import VueRouter from "vue-router"; Vue.use(VueRouter) const router = new VueRouter({ ...... }) export default router
1. 全局路由守卫
- 全局前置路由守卫
- 全局后置路由守卫
(1)简单使用
import Vue from 'vue';
import VueRouter from "vue-router";
import MyAbout from "@/components/MyAbout.vue";
import MyHome from "@/components/MyHome.vue";
Vue.use(VueRouter)
const router = new VueRouter({
......
})
// 每次路由切换之前调用、初始化调用
router.beforeEach((to, from, next) => {
console.log('前置', to, from, next)
next() // 放行
})
// 每次路由切换之后调用、初始化调用
router.afterEach((to, from) => {
console.log('后置', to, from)
})
export default router
(2)组件鉴权
判断哪个组件需要权限才可以访问
- 在 meta 属性里面配置组件的元信息,表示组件是否需要鉴权
- meta 属性是专门留给我们自定义属性的
声明鉴权属性
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/about',
component: MyAbout,
meta: {
isAuth: true,
}
}, {
path: '/home',
component: MyHome,
meta: {
isAuth: false,
}
}
],
})
进行鉴权
// 每次路由切换之前调用、初始化调用
router.beforeEach((to, from, next) => {
console.log('前置')
if (to.meta.isAuth) {
let isOk = true
if (isOk) {
console.log('需要鉴权,权限符合,放行')
next()
} else {
console.log('需要鉴权,权限不符合,不放行')
}
} else {
console.log('不需要鉴权,放行')
next()
}
})
// 每次路由切换之后调用、初始化调用
router.afterEach((to, from) => {
console.log('后置', to, from)
})
(3)应用:修改网页标题
每次切换路由,查看组件信息时,修改网页标题,使其更符合当时的查看状态
每个组件保存一个标题
const router = new VueRouter({
routes: [
{
path: '/about',
component: MyAbout,
meta: {
isAuth: true,
title: '关于'
}
}, {
path: '/home',
component: MyHome,
meta: {
isAuth: false,
title: '主页'
}
}
],
})
前置路由守卫实现
router.beforeEach((to, from, next) => {
console.log('前置')
if (to.meta.isAuth) {
let isOk = true
if (isOk) {
console.log('需要鉴权,权限符合,放行')
next()
document.title = to.meta.title || '默认标题'
} else {
console.log('需要鉴权,权限不符合,不放行')
}
} else {
console.log('不需要鉴权,放行')
next()
document.title = to.meta.title || '默认标题'
}
})
后置路由守卫实现
router.afterEach((to, from) => {
console.log('后置', to, from)
document.title = to.meta.title || '默认标题'
})
虽然配置了路由守卫修改网页标题,但是在首次加载页面时,会出现瞬间的网页标题切换的变化,根本解决办法:修改
package.json
配置文件
2. 独享路由守卫
进入当前路由之前调用,专属于当前组件的路由守卫
import Vue from 'vue';
import VueRouter from "vue-router";
import MyAbout from "@/components/MyAbout.vue";
import MyHome from "@/components/MyHome.vue";
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{
path: '/about',
component: MyAbout,
meta: {
isAuth: true,
title: '关于'
},
beforeEnter(to, from, next) {
console.log('前置')
let isOk = true
if (isOk) {
console.log('独享路由守卫鉴权,权限符合,放行')
next()
} else {
console.log('独享路由守卫鉴权,权限不符合,不放行')
}
}
}, {
path: '/home',
component: MyHome,
meta: {
isAuth: false,
title: '主页'
}
}
],
})
// 每次路由切换之后调用、初始化调用
router.afterEach((to, from) => {
console.log('后置', to, from)
document.title = to.meta.title || '默认标题'
})
export default router
3. 组件内路由守卫
也可以把它当成钩子函数
仅当通过路由规则进入组件时调用,手动在模板里面写的组件标签不算,如下
<MyAbout></MyAbout>
简单使用
<script>
export default {
name:'About',
// 通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
if(true){
next()
}else{
alert('无权限查看!')
}
},
// 通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
next()
}
}
</script>