路由
路由(router)就是对应关系。
SPA 与前端路由SPA 指的是一个web 网站只有唯一的一个HTML 页面,所有组件的展示与切换都在这唯一的一个页面内完成。此时,不同组件之间的切换需要通过前端路由来实现。
结论:在SPA 项目中,不同功能之间的切换,要依赖于前端路由来完成!
路由就是Hash 地址(#)与组件之间的对应关系。
前端路由的工作方式
1.用户点击了页面上的路由链接
2.导致了URL 地址栏中的Hash 值发生了变化
3.前端路由监听了到Hash 地址的变化
4.前端路由把当前Hash 地址对应的组件渲染都浏览器中
vue-router的基本用法
vue-router是vue.js 官方给出的路由解决方案。它只能结合vue 项目进行使用,能够轻松的管理SPA 项目中组件的切换。
vue-router 的官方文档地址:router.vuejs.org/zh/
vue-router 安装和配置的步骤
1.安装vue-router 包
npm i vue-router@3.5.2 -S
2.创建路由模块
router/index.js
// 1.导入Vue和VueRouter的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 2.调用Vue.use()函数,把VueRouter安装为Vue插件
Vue.use(VueRouter)
// 3.创建路由的实例对象
const router = new VueRouter()
// 4.向外共享路由的实例对象
export default router
3.导入并挂载路由模块
main.js
// 导入路由模块,拿到路由的实例对象
// 在进行模块化导入时,如果给定的是文件夹,则默认导入这个文件夹下名字叫做index.js的文件
import router from '@/router/index.js'
new Vue({
render: h => h(App),
// 在vue项目中要想把路由用起来,必须把路由实例对象,通过下面的方式进行挂载
// router:路由的实例对象 router:router
router
}).$mount('#app')
4.声明路由链接和占位符
路由连接 router-link
占位符 router-view
App.vue
<!-- 当安装和配置了vue-router后,就可以使用router-link来替换普通的a链接 -->
<!-- <a href="#/home">首页</a>
<a href="#/movie">电影</a>
<a href="#/about">关于</a> -->
<router-link to="/home">首页</router-link>
<router-link to="/movie">电影</router-link>
<router-link to="/about">关于</router-link>
<hr>
<!-- 只要在项目中安装和配置了vue-router,就可以使用router-view这个组件 -->
<!-- 起到占位符的作用 -->
<router-view></router-view>
声明好路由链接和占位符之后,需要在路由文件中导入组件和声明链接和组件所对应的路由匹配规则。
router/index.js
// 1.导入Vue和VueRouter的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入需要的组件
import Home from '@/components/Home.vue'
import Movie from '@/components/Movie.vue'
import About from '@/components/About.vue'
// 2.调用Vue.use()函数,把VueRouter安装为Vue插件
Vue.use(VueRouter)
// 3.创建路由的实例对象
const router = new VueRouter({
// routes是一个数组,作用是定义hash地址和组件之间的对应关系
routes: [
// 路由规则
// {path:'/路径',component:要展示的组件}
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About }
]
})
// 4.向外共享路由的实例对象
export default router
路由重定向
路由重定向指的是:用户在访问地址A 的时候,强制用户跳转到地址C ,从而展示特定的组件页面。通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由的重定向。
const router = new VueRouter({
// routes是一个数组,作用是定义hash地址和组件之间的对应关系
routes: [
// 路由重定向规则
// 当用户访问 / 的时候,通过redirect属性跳转到 /home 对应的路由规则
{ path: '/', redirect: '/home' },
// 路由规则
// {path:'/路径',component:要展示的组件}
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About }
]
})
嵌套路由
通过路由实现组件的嵌套展示,叫做嵌套路由。
点击父级路由链接显示模板内容。
模板内容中又有子级路由链接。点击子级路由链接显示子级模板内容。
在About.vue 组件中,声明tab1 和tab2 的子路由链接以及子路由占位符。
About.vue
<template>
<div class="about_container">
<h2>About组件</h2>
<!-- 子集路由连接 -->
<router-link to='/about/tab1'>tab1</router-link>
<router-link to='/about/tab2'>tab2</router-link>
<hr>
<!-- 子级路由占位符 -->
<router-view></router-view>
</div>
</template>
在src/router/index.js 路由模块中,导入需要的组件,并使用children 属性声明子路由规则。
{
path: '/about',
component: About,
//路由重定向,打开About页面就展示tab1
redirect: '/about/tab1',
children: [
// 子路由规则
{ path: 'tab1', component: Tab1 },
{ path: 'tab2', component: Tab2 }
]
}
默认子路由:如果children数组中,某个路由规则的path值为空字符串,则这条路由规则叫做默认子路由。
<!-- 默认子路由对应的路由连接 -->
<router-link to='/about'>tab1</router-link>
{
path: '/about',
component: About,
children: [
// 子路由规则
// 默认子路由:如果children数组中,某个路由规则的path值为空字符串,则这条路由规则叫做默认子路由
{ path: '', component: Tab1 },
{ path: 'tab2', component: Tab2 }
]
}
动态路由
动态路由指的是:把Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在vue-router 中使用英文的冒号(:)来定义路由的参数项。
App.vue
<router-link to="/movie/1">泰坦尼克号</router-link>
<router-link to="/movie/2">北京爱情故事</router-link>
<router-link to="/movie/3">少年的你</router-link>
router/index.js
{ path: '/movie/:mid', component: Movie },
在动态路由渲染出来的组件中,可以使用this.$route.params 对象访问到动态匹配的参数值。
Movie.vue
<template>
<div class="Right-container">
<!-- this.$router 是路由的参数对象 -->
<h2>Movie组件----{{ this.$route.params.mid }}</h2>
</div>
</template>
为了简化路由参数的获取形式,vue-router 允许在路由规则中开启props 传参。
router/index.js
// 可以为路由规则开启props传参,从而方便的拿到动态参数的值
{ path: '/movie/:mid', component: Movie, props: true },
Movie.vue
<template>
<div class="Right-container">
<h2>Movie组件-----{{ mid }}</h2>
</div>
</template>
export default {
name: 'Movie',
// 接收props数据
props: ['mid']
}
注:
1.hash路径中斜线后面的参数叫路径参数,在路由参数对象中,需要使用this.$router.params来访问路径参数。
2.hash地址中?后面的参数项叫做查询参数,在路由参数对象中,需要使用this.$router.query来访问查询参数。
3.在this.$router中,path只是路径部分,fullPath是完整的地址。
/movie/2?name=zs&age=20 是fullpath的值;
/movie/2 是path 的值,不包括查询参数的值。
- this.router 是路由的导航对象
声明式导航和编程式导航
在浏览器中,点击链接实现导航的方式,叫做声明式导航。
例如:普通网页中点击< a > 链接、vue 项目中点击< router-link> 都属于声明式导航。
在浏览器中,调用API 方法实现导航的方式,叫做编程式导航。
例如:普通网页中调用location.href 跳转到新页面的方式,属于编程式导航
vue-router 中的编程式导航API
vue-router 提供了许多编程式导航的API,其中最常用的导航API 分别是:
①this.$router.push('hash 地址')
- 跳转到指定hash 地址,并增加一条历史记录
②this.$router.replace('hash 地址')
- 跳转到指定的hash 地址,并替换掉当前的历史记录
<template>
<div class="Left-container">
<h2>Home组件</h2>
<hr>
<button @click='gotoLK'>通过push方法跳转到‘泰坦尼克号’界面</button>
<button @click='gotoLK1'>通过replace方法跳转到‘泰坦尼克号’界面</button>
</div>
</template>
methods: {
gotoLK () {
this.$router.push('/movie/1')
},
gotoLk1 () {
this.$router.replace('/movie/2')
}
}
③this.$router.go(数值n)
- 实现导航历史前进、后退
<template>
<div class="Right-container">
<h2>Movie组件</h2>
<hr>
<button @click="goback">后退</button>
</div>
</template>
methods: {
goback () {
// go(-1)表示后退一层
// 如果后退的层数超过上限,则原地不动
this.$router.go(-1)
}
}
$router.go 的简化用法:
在实际开发中,一般只会前进和后退一层页面。
因此vue-router 提供了如下两个便捷方法:
①$router.back()
- 在历史记录中,后退到上一个页面
②$router.forward()
- 在历史记录中,前进到下一个页面
<template>
<div class="Right-container">
<h2>Movie组件</h2>
<!-- 当行内使用编程式导航的时候,this必须被省略 -->
<button @click="$router.back()">后退</button>
<button @click="$router.forward()">前进</button>
</div>
</template>
导航守卫
导航守卫可以控制路由的访问权限。
全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫。
因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制。
全局前置守卫的回调函数中接收3 个形参。
router/index.js
// 写在创建路由实例之后
// 为router实例对象声明全局前置导航守卫
// 只要发生了路由的跳转,就会触发回调函数fn
router.beforeEach(function (to, from, next) {
// to 表示将要访问的路由的信息对象
// from表示将要离开的路由的信息对象
// next()函数表示放行的意思
})
next 函数的3 种调用方式:
当前用户拥有后台主页的访问权限,直接放行:next()
当前用户没有后台主页的访问权限,强制其跳转到登录页面:next('/login')
当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)
使用全局前置守卫控制后台主页的访问权限
router.beforeEach(function (to, from, next) {
// 1.拿到用户将要访问的hash地址
// 2.判断hash地址是否等于/main
// 2.1 如果等于 /main,证明需要登录之后才能访问
// 2.2 如果不等于 /main,则不需要登录,直接放行
// 3.如果访问的地址是 /main,则需要读取localStorage中的token值
// 3.1 如果有token,则放行
// 3.2 如果没有token,则强制跳转到 /login登录页
if (to.path === '/main') {
// 如果要访问后台主页,判断是否有token
const token = localStorage.getItem('token')
if (token) {
// 存在token,放行
next()
} else {
// 没有token,强制进行登录
next('/login')
}
} else {
// 不访问后台主页,直接放行
next()
}
})