Vue3-09 Vue Router
Vue3学习笔记-09 Vue Router
For Vue3
安装
| 1 | yarn add vue-router@4 | 
创建路由实例
创建一个Hash模式的最简单路由并应用:
| 1 | import {createApp} from 'vue'; | 
历史记录模式
使用createWebHashHistory()创建Hash模式,使用createWebHistory()创建HTML5模式,并应用在createRouter的history选项
推荐使用HTML5模式,但是需要在服务器上添加回退路由,配置实例参考官网。
要注意,如果使用HTML5模式,vue.config.js中的publicPath需要配置为绝对路径'/',不应该配置为相对路径,否则会出现资源找不到的情况!
路由匹配
在参数中自定义正则
在动态匹配路由时,如果有两个路径相同的动态路由,可以再括号中为参数指定自定义正则,例如为orderId指定数字匹配:
| 1 | const routes = [ | 
这样,/25就会匹配第/:orderId,其他情况会匹配/:productName,路由的定义顺序不重要,因为自定义正则有着更高的优先级
要主要确保转义\
可重负参数
如果有需要匹配多个部分的路由,例如/first/second/third,使用*(0个或多个)和+(一个或多个)将参数标记为可重复
| 1 | const routes = [ | 
这将提供一个参数数组,使用命名路由时也需要传递数组。同时也可以通过在右括号天津嘉它们与自定义正则结合使用
| 1 | const routes = [ | 
可选参数
使用?来将一个参数标记为可选:
| 1 | const routes = [ | 
命名视图
如果希望同级展示多个视图,在同一个组件中存在多个<router-view>,这个时候就可以使用命名视图,例如:
| 1 | <router-view class="view left-sidebar" name="LeftSidebar"></router-view> | 
在配置时,多个视图需要配置多个组件在components选项上,key值为<router-view>的name:
| 1 | const router = createRouter({ | 
利用命名视图也可以创建嵌套视图的复杂布局,例如下面的例子:
| 1 | <!-- UserSettings.vue --> | 
Nav只是一个常规组件。UserSettings是一个视图组件。UserEmailsSubscriptions、UserProfile、UserProfilePreview是嵌套的视图组件。
配置时:
| 1 | { | 
重定向和别名
重定向
重定向的目标除了路径和命名路由外,还可以是一个方法,这个方法接受目标路由作为参数,动态返回重定向目标
| 1 | const routes = [ | 
注意,导航守卫并不会应用在跳转路由上,只会应用在其跳转的目标路由上
别名
alias可以接收数组,可以接受绝对路径从而避免嵌套结构的限制,如果路由有参数,确保在别命中包含参数
| 1 | const routes = [ | 
路由组件传参
把路由参数作为组件的Props传递以组件,避免组件与Route耦合,有三种模式:
(1)布尔模式
将props设置为true,route.params将被设置为组件的Props
| 1 | const User = { | 
对于命名视图,需要为每个视图定义Props配置:
| 1 | const routes = [ | 
(2)对象模式
当props是一个对象,会将对象中的属性设置为组件的Props,适合于Props为静态的情况
| 1 | const routes = [ | 
(3)函数模式
props可以是一个函数,接受当前路由作为参数,返回一个对象作为组件的Props
| 1 | const routes = [ | 
导航守卫
导航守卫可以返回值:
- false,取消当前导航
- 一个路由地址,就像调用router.push一样
- 抛出Error,取消导航,并调用router.onError注册的回调
- undefined或- true,导航有效,调用下一个导航守卫
| 1 | router.beforeEach(async (to, from) => { | 
next是第三个参数,仍然被支持,但是根据上面的描述,完全可以不通过next完成导航,使用next经常会出现调用多次或者不被调用的问题,而通过返回值来确定导航是否有效会确保戴航始终有效
路由元信息
通过扩展RouteMeta接口来输入meta字段:
| 1 | // typings.d.ts or router.ts | 
组合式API
在setup中访问路由和当前路由
在setup中不能使用this,所以需要引入useRouter和useRoute函数代替this.$router和this.$route
route对象是一个响应式对象,属性都可以监听,但是应该避免监听整个route对象以提升性能:
| 1 | import { useRoute } from 'vue-router' | 
导航守卫
可以通过导入onBeforeRouteLeave和onBeforeRouteUpdate两个函数,来使用组件内的导航守卫。
可以用在任何由<router-view>渲染的组件中,不必像组件内守卫那样直接用在路由组件上
过渡动效
需要使用v-slot API
单个路由的过渡
可以将路由的元信息和动态name结合在一起,放在<transition>上
| 1 | const routes = [ | 
| 1 | <router-view v-slot="{ Component, route }"> | 
基于路由的动态过渡
可以根据目标路由和当前路由的关系,动态的确定使用过渡,需要利用afterEach导航守卫,下面的例子是根据路径的深度动态添加transitionName
| 1 | router.afterEach((to, from) => { | 
导航故障
检测导航故障
router.push是一个异步方法,它会返回一个Promise,如果导航被阻止,用户停留在同一个页面上,router.push返回的Promise的解析值将是Navigation Failure,否则导航成功是,router.push的返回结果是一个falsy值(通常是undefined),这样来区分导航是否成功:
| 1 | const navigationResult = await router.push('/my-profile') | 
Navigation Failure是一个带有额外属性的Error实例,通过这个实例来判断哪些导航被阻止了及其原因,检查导航结果需要使用isNavigationFailure和NavigationFailureType
| 1 | import { NavigationFailureType, isNavigationFailure } from 'vue-router' | 
导航故障的fail实例会暴露to和from属性,反应当前失败导航的当前位置和目标位置
鉴别导航故障
有不同的情况会导致导航终止,可以使用isNavigationFailure和NavigationFailureType来区分类型:
- aborted:在导航守卫中返回- false或者调用- next(false)中断了本次导航。
- cancelled: 在当前导航还没有完成之前又有了一个新的导航。比如,在等待导航守卫的过程中又调用了- router.push。
- duplicated:导航被阻止,因为我们已经在目标位置了。
isNavigationFailure接受两个参数,第一个参数是Navigation Failure实例,第二个参数是决具体的导航失败的枚举值(通过NavigationFailureType获取),如果不传入第二个参数,则只判断当前Error是不是Navigation Failure
NavigationFailureType包含所有可能导航失败类型的枚举值,不要使用数组,永远只使用枚举值
检测重定向
重定向不会阻止导航,而是创建一个新的导航,可以读取路由地址的redirectedFrom属性,判断重定向:
| 1 | await router.push('/my-profile') | 
动态路由
通过addRoute和removeRoute来完成动态路由功能,但是这两个函数,只注册路由,如果新增路由与当前位置匹配,还需要调用router.push或router.replace来手动导航,才能显示该新路由
添加路由
只有一个路由的配置情况下:
| 1 | const router = createRouter({ | 
进入任何页面都会显示Article组件,在组件上为/about添加一个新路由:
| 1 | router.addRoute({ path: '/about', component: About }) | 
这时页面不会有任何改变,需要手动调用replace方法来改变当前位置:
| 1 | router.addRoute({ path: '/about', component: About }) | 
如果要等待新路由的完成,可以使用await router.replace()
在导航守卫中添加路由
在导航守卫中添加或删除路由,需要通过返回新的位置来触发重定向:
| 1 | router.beforeEach(to => { | 
上面的例子实际上你是在替换要跳转的导航,在实际场景中,添加路由的欣慰更有可能是发生在导航之外,那么就不需要替换当前的导航了
添加嵌套路由
router.addRoute除了添加单个路由之外,还可以将路由的name作为第一个参数传递,这可以添加嵌套的路由,就像通过children添加的一样
| 1 | router.addRoute({ name: 'admin', path: '/admin', component: Admin }) | 
这等效于
| 1 | router.addRoute({ | 
删除路由
当路由被删除时,所有的别名和子路由都会被删除。有几种方法来删除当前路由:
(1)添加一个名称相同的路由,那么就会删除之前的路由“
| 1 | router.addRoute({ path: '/about', name: 'about', component: About }) | 
(2)如果是动态添加的路由,那么可以调用router.addRoute
| 1 | const removeRoute = router.addRoute(routeRecord) | 
(3)使用router.removeRoute按名称删除路由
| 1 | router.addRoute({ path: '/about', name: 'about', component: About }) | 
为了避免名字冲突,可以使用Symbol作为路由的名称
查看现有路由
- router.hasRoute():确认是否存在指定名称的路由,接受类型为- string或者- symbol的参数
- router.getRoutes:获取所有路由记录的完整列表
从Vue2迁移
创建路由实例的改变
new Router变为createRouter
Vue Router不再是一个类,而是一组函数:
| 1 | // 以前是 | 
路由模式改变
mode: 'history'被history配置替换:
- "history":- createWebHistory()
- "hash":- createWebHashHistory()
- "abstract":- createMemoryHistory(),用于SSR的情况
| 1 | import { createRouter, createWebHistory } from 'vue-router' | 
base配置改变
base作为createWebHistory的第一个参数传递
路由配置
删除了通配符路由*
必须使用自定义的正则参数来定义全部路由
| 1 | {path: '/:pathMatch(.*)', component: NotFound} | 
<keep-alive>和<transition>
<keep-alive>和<transition>需要通过v-slotAPI在<router-view>内部使用
| 1 | <router-view v-slot="{ Component }"> | 
细节还是挺多的,更详细的还是看文档吧。