基础部分
带参数的动态路由匹配
基本的,路径参数用:
表示,同时,这个参数值用this.$route.params
来访问。
const User = {template: '<div> {{ $route.params.id }} </div>'}
routes = [{path: '/user/:id',component:User}]
但使用这种模式的时候,/user/:id
可以匹配到/user/zqc
或者/user/zqc1
等,当从zqc
跳转到zqc1
的时候,组件并没有经过销毁再创建,而是直接复用,这时候就不会触发对应的生命周期函数,所以需要使用watch监听一下。
const User = {
template: '<div>User{{ $route.params.id }} = {{this.old}}-->{{this.new}}</div>',
created() {
this.$watch(
() => this.$route.params,
(toParams, previousParams) => {
// 对路由变化做出响应...
this.new = toParams
this.old = previousParams
}
)
},
}
404捕获
在路径参数后面添加一个括号
,在括号内部添加一个正则表达式就可以进行自定义的路由匹配,而当匹配到所有“有效路由”无法匹配的路由时,将由404呈现。
const routes = [
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
// 将匹配以 `/user-` 开头的所有内容
{ path: '/user-:afterUser(.*)', component: User1 },
]
路由参数中的自定义正则
场景引入:在/user/:id
中存在id为数字和其他这两种情况,如何匹配?
方法一:加入一个静态路由部分
匹配 /user/number/3549
和/user/other/25h43kl
方法二:进行正则匹配
const routes = [{
path: '/user',
component: User,
children: [{
path: '/:id(\\d+)*',
component: Number,
}, {
path: '/:id',
component: Other,
}, ], }, ]
可重复的参数
*
(0 个或多个)和 +
(1 个或多个)
const routes = [
// /1、 /123
{ path: '/:orderId(\\d+)', component: Order},
// /、 /1 、 /2312
{ path: '/:orderId(\\d*)', component: Order1},
// /12 、 /12/134/534
{ path: '/:orderId(\\d+)+', component: Order2},
// /、 /1/4 、 /2312
{ path: '/:orderId(\\d+)*', component: Order3},
]
以及一个可选参数:?
修饰符(0 个或 1 个),这个? 与* 不同在?不能重复
const routes = [
// /users 和 /users/1f23
{ path: '/users/:userId?' }
]
编程式导航
声明式:<router-link :to="...">
编程式: router.push(...)
// 字符串路径
router.push('/users/eduardo')
// 带有路径的对象
router.push({ path: '/users/eduardo' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })
注意的是:name配套params path配套query
替换当前位置
使用replace()
函数,不会往历史记录题添加新记录,只是修改了当前记录。
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })
任意跳转
使用go()
函数,里面传递一个实数,表示跳转多少步
route.go(num) // 1||-1||423
命名视图
当出现一个布局包含多个视口时候可以使用命名视图表明不同视口使用哪个组件。
const router = createRouter({
routes: [
{
path: '/',
components: {
default: Home,
Sidebar,
},
},
],
})
<router-view class="sidebar" name="Sidebar"></router-view>
<router-view class=" main"></router-view>
重定向和别名
在写 redirect
的时候,可以省略 component
配置,因为它从来没有被直接访问过,所以没有组件要渲染。但是嵌套路由有 children
和 redirect
属性,它也应该有 component
属性。
const routes = [{ path: '/home', redirect: '/' },
{ path: '/home', component: Home, alias: ['/', '/hm'] }]
别名和重定向的表现差不多,但是重要的是,使用别名的时候范围的路由是不会从/ 、 /hm
变成/home
的,当重定义会修改地址栏里的路由。
路由组件传参
文档原文:
在你的组件中使用 $route
会与路由紧密耦合,这限制了组件的灵活性,因为它只能用于特定的 URL。虽然这不一定是件坏事,但我们可以通过 props
配置来解除这种行为。这允许你在任何地方使用该组件,使得该组件更容易重用和测试。(并没有感到有什么优势)
const User = {
// 请确保添加一个与路由参数完全相同的 prop 名
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const routes = [{ path: '/user/:id', component: User, props: true }]
进阶部分
导航守卫
1、全局守卫: router.beforeEach
2、全局解析守卫: router.beforeResolve
3、全局后置钩子: router.afterEach
4、路由独享的守卫: beforeEnter
5、组件内的守卫: beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
全局前置守卫
最重要的是第三个参数next,这个守卫不管有多少个判断,每种可能也得有一个出口,否则无法进行正常跳转
router.beforeEach((to, from, next) => {
if (!isLoginIn) next({ name: 'Login' })
else next()
})
全局解析守卫
是确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,被调用
router.beforeResolve
是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。
全局后置钩子
这种不会接收next,也不该百年导航本身,应用于分析更改页面标题或者声明页面等功能。
路由独享守卫
beforeEnter
守卫 只在进入路由时触发,不会在 params
、query
或 hash
改变时触发。
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
return false
},
},
]
组件内的守卫
beforeRouteEnter
不可访问thisbeforeRouteUpdate
可访问thisbeforeRouteLeave
可访问this
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫(2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。
数据获取
有2种方式
方法一:完成导航之后在created获取数据,期间使用加载中……占位
方法二:在完成导航之前,使用beforeRouteEnter()进行获取,获取到数据后只调用next,期间最好也用加载种……来占位。