路由
配置
路由:route
安装:npm i vue-router@3
对于安装的版本 v2 安装 3版本,v3 安装 4版本
// 导入依赖
import VueRouter from 'vue-router'
// 使用路由
Vue.use(VueRouter)
...
new Vue({
...
router: 路由对象
...
})
创建路由器对象(router/index.js
),然后导入替换掉中文部分
使用
在 index.js 中输入以下内容
import VueRouter from "vue-router";
export default new VueRouter({
routes: [
{
// 以下写路由的 key
path: "",
// 以下写组件
component: 组件,
// 子集路由
children: [
{path: "", component: 组件}
// ...
]
}
]
})
routes中每一个对象就是一个路由,每个路由都是由 path 和 component 组成
子集路由也就是在路由内的路由,对于子集路由来说 path 不需要加 /
,子集路由可以进行套娃使用
路由配置完成之后,在组件中使用如下
<!-- 这个位置是用来决定下方的 view 展示什么组件 -->
<RouterLink active-class="类选择器名称" to="配置的路由key">Name</RouterLink>
<!-- 将来会在这个位置进行组件的展示和替换 -->
<RouterView/>
在 RouterLink
中对于根路由写为 /xxx
即可,如果是子集路由需要从根路由到子路由如:/xxx/xxx/xxx
active-class
:这个参数为了实现组件的激活状态样式切换,当这个组件被激活时,会引用属性值的css
传参(query)
在 RouterLink
发送内容时使用地址栏的方式进行传参,因为参数不能固定死,所以采用单项绑定进行传值,而且也可以使用计算属性进行传参
<template>
<div id="app">
<ul>
<li>
<!-- 字符串拼接的方式 -->
<RouterLink :to="`/henan?a1=${hn[0]}&a2=${hn[1]}&a3=${hn[2]}`">河南</RouterLink>
</li>
<li>
<!-- 对象的方式 -->
<RouterLink :to="{
path: '/hebei',
query: {
a1: hb[0],
a2: hb[1],
a3: hb[2]
}
}">河北</RouterLink>
</li>
</ul>
<RouterView/>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
hb: [1, 2, 3],
hn: [4, 5, 6]
}
}
}
</script>
所有的路由组件都拥有一个 $route
属性,通过这个属性可以获取到该路由组件关联的路由对象
在子组件中使用 query
接收参数,格式为:$route.query.参数key
<template>
<div>
<ul>
<li>{{ $route.query.a1 }}</li>
<li>{{ $route.query.a2 }}</li>
<li>{{ $route.query.a3 }}</li>
</ul>
</div>
</template>
链接同时激活问题:这是由于路径一致问题所导致的,路由会自动激活所有路径一致的内容如下
<RouterLink :to="`/dq/xs?a1=${hn[0]}&a2=${hn[1]}&a3=${hn[2]}`">河南</RouterLink> <RouterLink :to="`/dq/xs?a1=${hb[0]}&a2=${hb[1]}&a3=${hb[2]}`">河北</RouterLink>
解决方法:把路由配置文件中的内容设置为不一致
// 原 path: '/dq', component: 组件, children: [ { path: "xs", component: 组件 } ] // 改 path: '/dq', component: 组件, children: [ { path: "xs1", component: 组件 }, { path: "xs2", component: 组件 } ]
传参(params)
这种方式是路径传参,跟MVC的 /xxx/{data}/xxx
相像
<!-- 字符串形式 -->
<RouterLink :to="`/dq/${hn[0]}/${hn[1]}}`">河南</RouterLink>
<!-- 对象形式 -->
<RouterLink :to="{
name: '名称',
params: {
a1: xxx,
a2: xxx
}
}">河北</RouterLink>
如果使用对象形式,那么不能使用 path 必须使用 name
在路由配置文件中
{
path: '/dq/:a1/:a2',
component: 组件,
}
在这种情况中以 :
开头的被标记为参数
在使用时参数时,使用 {{ $route.params.参数 }}
参数优化(props)
在引用参数的时候需要在前面写上很多的固定的内容,这部分是可以简化的,只需要在路由的配置页进行一个配置即可
{
path: '/dq/:a1/:a2',
component: 组件,
// 使用 props 的函数式写法,route 参数会被自动传过来代表了当前的路由对象
props(route) {
return {
a1: route.params.a1,
a2: route.params.a2
}
},
// 这种方式也可以达到跟上面一样的效果,但是只支持 params 形式的传参
props: true
}
以上就是简单的配置,然后再使用的组件中使用 props 来进行引用即可
<template>
<div>
<ul>
<li>{{ a1 }}</li>
<li>{{ a2 }}</li>
<li>{{ a3 }}</li>
</ul>
</div>
</template>
<script>
export default {
props: ['a1', 'a2', 'a3']
}
</script>
路由命名
由于在路由多的情况下 path 会非常长,官方提供了一种属性 name 给路由加上名称然后直接使用即可
{
name: "名称"
path: "xs2",
component: 组件
}
使用名称
<RouterLink :to="{
name: "名称",
query: {
a1: hb[0],
a2: hb[1],
a3: hb[2]
}
}">河北
</RouterLink>
只能实在以上这种对象形式中才能使用
接受参数(V3)
在Vue3的编程式路由中通过 query
或者 params
等传递的参数无法在使用 $route
接收,可以使用 useRoute()
函数进行接收
import {useRoute} from "vue-router";
useRoute().query
useRoute().params
...
编程式路由
在以上的使用场景中,所有路由跳转都是由 RouterLink
标签进行的,该标签会在编译后转换成 a 标签,编程式路由就是通过方法调用进行跳转路由,详细如下:
<template>
<div id="app">
<button @click="henan">河南</button>
<button @click="hebei">河北</button>
<RouterView/>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
hb: [1, 2, 3],
hn: [4, 5, 6]
}
},
methods: {
henan() {
// 以 push 方式跳转
this.$router.push({
name: 'henan',
params: {
a1: this.hn[0],
a2: this.hn[1],
a3: this.hn[2]
}
})
},
hebei() {
// 以 replace 方式跳转
this.$router.replace({
path: '/hebei',
query: {
a1: this.hb[0],
a2: this.hb[1],
a3: this.hb[2]
}
})
}
}
}
</script>
使用以上的方式需要获取到路由器(router)不是路由对象(route),通过路由器的push方法进行跳转路由
push和replace区别
把游览器比作一个栈,页面的前进和后退操作其实就是在不断的压栈和弹栈,这两种方法都是压栈的一种方式
push:以追加的方式进行一个压栈
replace:以替换的方式进行一个压栈
除了以上的两个API还有前进、前进几步、后退、后退几步等API
前进:this.$router.forward()
后退:this.$router.back()
前进与后退2步:this.$router.go(2 | -2)
Promise 对象
当在使用编程式导航的时候,push 和 replace 都会返回一个 Promise 对象,这个对象希望你通过参数的方式给它一个参数和两个回调函数。分别会在成功和失败时自动调用。
如果没有给他回调函数,那么当重复点击某一个导航按钮时会出现冗余异常,就会报错,解决方式就是加上两个回调函数即可
henan() {
// 以 push 方式跳转
this.$router.push({
name: 'henan',
params: {
a1: this.hn[0],
a2: this.hn[1],
a3: this.hn[2]
}
}, ()=> {
// 成功时调用
}, ()=> {
// 失败时调用
})
}
路由组件销毁
在默认的情况下,只要进行路由的切换,就会杀死被切换的组件,如果向在切换组件的时候保持住组件的活性,那么需要 <RouterView/>
外面添加上 <KeepAlive>
标签
keep-alive
标签可以保证切换组件的时候不销毁之前的路由组件
<KeepAlive>
<RouterView/>
</KeepAlive>
以上面形式编写那么所有的组件都不会进行销毁,但是可以使用 include
属性进行执行组件不会销毁
<KeepAlive include="组件名称">
<RouterView/>
</KeepAlive>
<!-- 以数组的形式 -->
<KeepAlive :include="['名称1','名称2']">
<RouterView/>
</KeepAlive>
两个额外的钩子
对于路由组件来说,除了8个基本的声明周期还有两个额外的钩子
- activated:在组件被切换到的时候执行
- deactivated:在组件被切走的时候执行
只有路由组件才拥有以上两个钩子函数
路由守卫
本质来说就是权限访问。在切换到某个组件的时候执行一段代码,这段代码专门用来鉴权。有权限可以切换,没有权限不可以切换
自定义属性
在路由鉴权的时候添加自定义属性进行校验判断这个路由是否需要进行鉴权,这样可以省去很大的精力
{
path: "/hebei",
component: HeBei,
meta:{
自定义属性:true
}
}
自定义属性只有在 meat
中才可以定义,使用时可以通过 路由对象.meat.属性名
来使用
全局前置路由守卫
书写位置:路由配置文件,创建配置之后,暴露配置之前
调用时机:在初始化的时候调用一次,往后在任何一次切换任意组件之前都会调用
router.beforeEach((to, from, next) => {
// ...
})
to:路由对象,表示到那个路由去
form:路由对象,表示从那个路由切换的
next:这是一个函数,调用该函数表示放行
全局后置路由守卫
书写位置:路由配置文件,创建配置之后,暴露配置之前
调用时机:初始化时执行一次,往后在任何一次切换完任意组件之后都会调用
router.afterEach((to, from) => {
// ...
})
to:路由对象,表示到那个路由去
form:路由对象,表示从那个路由切换的
没有next函数
局部路由守卫(Path)
书写位置:路由配置文件,route 对象中
调用时机:进入组件当前之前
{
path: "/hebei",
component: HeBei,
beforeEnter(to, from, next) {
// ...
}
// 没有 afterEach()
}
beforeEnter 与全局不同的是 beforeEnter 本身就是一个函数,不在需要回调函数
局部路由守卫(Component组件守卫)
书写位置:路由组件内部
export default {
// 进入路由组件之前执行
beforeRouteLeave(to, from, next) {
// ...
},
// 离开路由组件之前执行
beforeRouteEnter(to, from, next) {
// ...
}
}
普通组件不会触发,必须得是路由组件
地址栏 - 问题
路径中 # 后面的路径被称为 hash 值,hash 值不会作为请求路径的一部分发送给服务器
地址:http://localhost/#/hebei
路由的两种路径模式:hash模式(默认)、history模式
配置 history 模式:在路由的index中配置 mode 属性(不配置默认是hash)
const router = new VueRouter({
mode: 'history',
routes: [ ... ]
})
export default router;
history 问题
在 hash 模式下 # 后面的值是不会包含在请求中的,但是如果是在 history 模式下,使用路由地址栏地址改变后刷新的话会造成 404 异常
一站式解决方法
只需要在后端进行判断404错误然后返回index页面即可
前后分离解决方法
使用中间件如Nginx,配置404错误然后返回index页面