VueRouter 基础教程系列 🎉
VueRouter 知识结构体系图(大图预警)
router-link
props
to
目标路由地址,当被点击后,内部会调用 router.push() 进行导航。
replace
当被点击后,内部会调用 rotuer.replace() 进行导航,所以不会产生新的历史记录。
active-class & exact-active-class
active-class自定义链接激活的样式类,默认值:router-link-active。exact-active-class自定义链接精准激活的样式类,默认值:router-link-exact-active。
🤔 它们有什么区别吗? 很简单,一个路由记录的
matched中的所有匹配项都会激活active-class,而只有全path匹配的路由记录才会激活exact-active-class样式。
custom
是否取消 <router-link> 组件的默认点击行为,再结合 v-slot 便可实现自定义 router-link 组件。
<router-link to="/about" custom v-slot="{ navigate, route, href }">
<a :href="href" @click="navigate">{{ route.name }}</a>
</router-link>
v-slot
<router-link> 组件的 v-slot 公开了其在导航是内部保存的信息与行为。
| 属性/方法 | 说明 |
|---|---|
| href | 解析后的 URL,既要跳转的链接。 |
| route | 解析后的路由记录对象。 |
| navigate | 路由器的导航方法 |
| isActive | 链接是否被激活,返回值是一个布尔值。 |
| isExactActive | 链接是否被精准激活?返回值是一个布尔值。 |
<router-link
custom
to="/about"
v-slot="{ navigate, route, href, isActive, isExactActive }"
>
<a
@click="navigate"
:href="href"
:class="{
'router-link-active': isActive,
'router-link-exact-active': isExactActive,
}"
>{{ route.name }}</a
>
</router-link>
router-view
Props
name
为命名路由定义对应的视图渲染出口。默认为 default,如果有多个视图渲染出口,路由组件默认总是在最近的一个渲染出口输出。
v-slot
router-view 组件的 v-slot 暴露了两个非常有用的值,分别是要渲染的路由组件实例 component 以及当前的路由记录对象 route。
<router-view v-slot="{ Component, route }">
<transition @afterEnter="handleAfterEnter" :name="route.meta.transition">
<component :is="Component" />
</transition>
</router-view>
router-view 组件的 slot 经常会与 transition 以及 keep-alive 一同使用。
createRouter()
用来创建一个路由器对象,接收以下选项作为参数:
属性:
| 属性 | 说明 |
|---|---|
| history | 设置路由的模式,常用的是 createWebHistory。 |
| linkActiveClass | 全局设置链接激活时的样式类名。 |
| linkExactActiveClass | 全局设置链接精准激活时的样式类名。 |
| routes | 路由配置项 |
方法:
| 属性 | 说明 |
|---|---|
| scrollBehavior | 在页面之间导航时控制滚动的函数。可以返回一个 Promise 来延迟滚动。 |
| parseQuery | 用于解析查询的自定义实现。 |
| stringifyQuery | 对查询对象进行字符串化的自定义实现。 |
createWebHistory()
将路由模式设置为 HTML5 的 history 模式。
接收一个 base 参数用来设置路由的基准地址,这对应用地址不在域名的根目录下非常有用。
createWebHistory() // 没有 base,应用托管在域名 `https://example.com` 的根目录下。
createWebHistory('/folder/') // 给出的网址为 `https://example.com/folder/`
createWebHasHistory()
将路由模式设置为 hash 模式。hash 模式的优点在于无需服务端支持,但对于 SEO 非常差,同样支持接收一个 base 属性,用来设置路由的基准地址。
createMemoryHistory()
创建一个基于内存的历史记录。这个历史记录的主要目的是处理 SSR。它在一个特殊的位置开始,这个位置无处不在。如果用户不在浏览器上下文中,它们可以通过调用 router.push() 或 router.replace() 将该位置替换为启动位置。
Router
路由器对象,这里着重介绍它的几个比较复杂的成员属性或方法。
currentRoute
获取当前的路由记录对象。
import { defineComponent, getCurrentInstance } from "vue";
import { useRoute, useRouter } from "vue-router";
export default defineComponent({
setup() {
const vm = getCurrentInstance().proxy;
const router = useRouter();
const route = useRoute();
console.log(route); //注意它是一个 proxy 的路由记录对象。
console.log(vm.$route);
console.log(router.currentRoute.value);
},
});
isReady()
值是一个 Promise,当路由器完成初始化导航时触发。这意味着它已经解析了所有与初始路由相关的异步钩子和异步组件。
router.beforeEach(() => {
console.log('beforeEach')
});
router.afterEach(() => {
console.log('afterEach')
});
router.beforeResolve(() => {
console.log('beforeResolve')
});
router.isReady().then(() => {
console.log('router is ready');
});
//执行顺序:beforeEach -> beforeResolve -> afterEach => router is ready
【在前端的使用场景】
当路由与 <transition> 组件一同使用时,会发现初始导航也有过渡效果,这个效果类似于为 <transition> 组件设置了 appear 属性一般。
究其原理,原因在于导航是异步解析的,在应用的初始挂载时,可能还未解析到路由组件,当路由组件解析完成后,便会再次触发 <transition> 组件的过渡效果。
解决办法很简单,那就是在初始导航准备完毕后再去挂载 Vue 应用。
const app = createApp({});
app.use(router);
router.isReady().then(()=>{
app.mount('app');
});
【 SSR 中的使用场景】
在服务端渲染,路由器的 isReady 方法能确保服务器和客户端的输出一致。
需要注意的是,服务端不的路由器不会像客户端那样可以自动从浏览器的 URL 中获取初始位置,服务端则需要手动推送初始位置。
onError()
路由器的错误处理程序,主要用来捕获不可预知的导航故障,捕获范围:
- 路由守卫中抛出的错误。
- 路由解析过程中导航还未确认时抛出的错误。
- 解析路由组件时发生的错误。
不能捕获的范围:
- 导航确认后的路由守卫抛出的异常,例如
afterEach守卫中抛出的错误。 - 路由组件内抛出的异常。
- 可预知的路由故障(此由路由器对象的结果返回)
resolve()
根据给定的路由地址,返回一个解析后的 route 对象。
路由地址既可以是简单的字符串也可以是一个配置对象。
getRoutes()
获取所有的路由记录配置对象。
hasRoute()
确认是否存在指定名称的路由(所以必须要是命名路由)。
if(hasRoute('User')) {}
路由守卫方法
- beforeEach() : 全局前置守卫。
- afterEach() : 全局后置守卫。
- beforeResolve() : 全局解析守卫。
路由导航方法
- go() : 横跨历史记录。
- forward() :前进。
- back() :后退。
- push() :通过在历史堆栈中推送一个 entry,以编程方式导航到一个新的 URL。
- replace() : 通过替换历史堆栈中的当前 entry,以编程方式导航到一个新的 URL。
动态路由方法
- addRoute()
- removeRoute()
Route
一个路由记录的相关配置项。
【属性:】
| 属性 | 说明 |
|---|---|
| path | 记录的路径。 |
| redirect | 重定向。 |
| children | 嵌套路由。 |
| alias | 路由别名,可以抹平路由地址与组件之间层级的映射关系 |
| name | 命名路由 |
| props | 向路由组件传递 props。 |
| meta | 向记录上附加自定义数据。 |
| component | 定义路由组件。 |
| components | 为不同的命名视图定义对应的路由组件。 |
【方法:】
| 方法 | 说明 |
|---|---|
| beforeEnter | 路由记录独有的导航守卫。 |
| props | 向路由组件传递 props,当是一个方法时,可以接收一个 route 作为参数。 |
| component | 定义异步路由组件或者是函数式组件 |
| components | 为不同命名视图定义对应的异步路由组件或函数式组件 |
【redirect】
如果路由是直接匹配的,那么重定向到哪里呢。重定向发生在所有导航守卫之前,并以新的目标位置触发一个新的导航。也可以是一个接收目标路由地址并返回我们应该重定向到的位置的函数。
【函数式组件】
如果你想使用函数式组件, 请确保在组件上添加一个 displayName。
import {RouterLink } from 'vue-router'
import { h } from 'vue';
const User = () => h(RouterLink, { to: 'user' }, ['user']);
const routes = [
{
path: 'user',
component: User
}
];
Composition API
useRouter()
获取当前的路由器对象。
useRoute()
获取当前的路由记录对象。
useLink()
以函数的方式调用 router-link 组件,然后获取其内部的 v-slot。
import { defineComponent } from "vue";
import { useLink, RouterLink } from "vue-router";
export default defineComponent({
props: {
...RouterLink.props,
},
setup(props) {
const { navigate, href, route, isActive, isExactActive } = useLink(props);
return {
navigate,
href,
route,
isActive,
isExactActive,
};
},
});
onBeforeRouteLeave()
组件将要离开时触发的导航守卫。类似于 beforeRouteLeave。
onBeforeRouteUpdate()
添加一个导航守卫,在当前位置即将更新时触发。类似于 beforeRouteUpdate。
START_LOCATION
路由所在的初始路由地址。可用于导航守卫中,以区分初始导航。
import { START_LOCATION } from 'vue-router'
router.beforeEach((to, from) => {
if (from === START_LOCATION) {
// 初始导航
}
})
NavigationFailure
路由导航方法的返回结果,由 Promise 进行包裹。
to
导航去的路由地址
from
导航来源的路由地址
type
导航故障的类型:NavigationFailureType
NavigationFailureType
包含所有可能导航失败类型的枚举,可以传递给 isNavigationFailure 来检查某些特定类型的失败。不要使用任何数值,总是使用诸如 NavigationFailureType.aborted 这样的变量。
| 成员 | 描述 |
|---|---|
| aborted | 终止导航是指由于导航守卫返回 false 或调用 next(false) 而失败的导航。 |
| cancelled | 取消导航是指由于最近的导航完成启动(不一定是完成)而失败的导航。 |
| duplicated | 重复导航是指在启动时已经在同一位置失败的导航。 |
isNavigationFailure()
检查导航结果是否存在故障或者是否为指定的故障。
const navigationFailure = await vm.$router.push('/user');
isNavigationFailure(navigationFailure);
isNavigationFailure(navigationFailure, NavigationFailureType.duplicated);
Component Injections
这些属性通过调用 app.use(router) 注入到每个子组件中。
实际上,你可以在
app.config.globalProperties中发现它们。
- $router
router 实例,路由器对象。
- $route
路由记录对象,当前激活的路由地址。这个属性是只读的,并且它的属性是不可改变的,但是它可以被观察。