1.动态路由
const router = new VueRouter({
routes:[
{path:'/user/:id',component:User}
]
})
<router-link to='/user/123'></router-link>
<router-link to='/user/456'></router-link>
//可通过this.$route.params.id获取到
2.导航守卫 ( beforeRouteUpdate),在组件里面监听路由变化,应用场景有:
当两个路由使用的是同一个组件时,路由之间的跳转不会重复渲染组件,也就不会调用生命周期,可以在beforeRouteUpdate里面进行相应的操作,记得要next(),路由才会进行跳转,具体应用场景可参考 Vue踩坑记录中的第一点
3.通配符 *,匹配任意路径
const router = new Router({
routes:[
{ path:'/user-*',componnent:User }, //匹配所有以'/user-'开头的路径
{ path:'*',component:Error } //匹配所有路劲
]
})
使用通配符,$route.params会自动添加一个pathMatch的参数,包含了路径中被匹配的部分
<router-link to="/user-12345"></router-link>
this.$route.params.pathMatch => 12345
4.嵌套路由
const router = new VueRouter({
routes:[
{ path:/user',component:User,
children:[
{ path:'name',component:Name },
{ path:'job',component:Job }
]
}
]
})
<router-link to="/user/name"></router-link>
<router-link to="/user/job"></router-link>
5.编程式导航:除了上面用router-link的方式跳转路由外,也可以通过编写代码来实现,借助router的实例方法:
A.router.push(location,onComplete,onAbort),该方法的参数可以是一个字符串路径,也可以是一个描述地址的对象,这个 方法会向history栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的URl
a.字符串
router.push('home')
b.对象
router.push({path:'home'})
c.命名的路由
router.push({name:'user',params:{userId:'123'}})
d.带查询参数,变成/register?plan=private
router.push({path:'register',query:{plan:'private'}})
e.e.需要注意的是,当提供了path时,params会被忽略,如果需要传递params
可以参考下面两种方法://user/123
router.push({name:'user',params:{userId:123}})
router.push({path:'user/123'})
f.onComplete和onAbort回调作为第二个和第三个参数,这些回调将会在导航成功完成(在所有的异步钩子被解析之后)或终止(导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由)的时候进行相应的调用
B.router.replace(location,onComplete,onAbort),和router.push很像,唯一不同的是,它不会向history添加新纪录,而是替换当前的记录,同样有声明式和编程式两种写法:
<router-link to='/user' replace></router-link> //声明式
router.replace('/user')
C.router.go(n),这个方法的参数是一个整数,意思是在history记录中向前或后退多少步,类似window.history.go(n)
a.在浏览器记录中前进一步,等同于history.forward()
router.go(1)
b.后退一步记录,等同于history.back()
router.go(-1)
c.前进3步记录
router.go(3)
d.如果history记录不够用,就是无效,什么也不会做
router.go(100)
D.以上三个导航方法(push,replace,go)在各类路由模式(history、hash、abstract)下表现一致
6.命名路由,有时候通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称
const router = new VueRouter({
routes:[
{
path:'/user/:userId',
name:'user',
component:User
}
]
})
以下两种方法都会把路由导航到/user/123
<router-link :to="{name:'user',params:{userId:123}}">User</router-link>
router.push({name:'user',params:{userId:123}})
7.命名视图,有时候想同时展示多个视图,而不是嵌套展示,这时候命名视图就派上用场了,给router-view设置名字,一个视图使用一个组件渲染,多个视图就需要多个组件
<div id="app">
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>
</div>
const router = new VueRouter({
routes:[
{
path:'/',
components:{
default:Foo,
a:Bar,
b:Baz
}
}
]
})
8.重定向和别名
A.重定向:
a.从/a重定向到/b
const router = new VueRouter({
routes:[
{
path:'/a',redirect:'/b'
}]
})
b.重定向的目标也可以是一个命名的路由
const router = new VueRouter({
routes:[
{
path:'/a',redirect:{name:'foo'}
}]
})
c.或者是一个方法,动态返回重定向目标
const router = new VueRouter({
routes:[
{
path:'/a',
redirect:to=>{
//方法接收 目标路由作为参数
//return 重定向的字符串路径/路径对象
}
}]
})
B.别名的功能可以让你自由地让UI结构映射到任意的URL,而不是受限于配置的嵌套路由结构(alias)
const router = new VueRouter({
routes:[
{
path:'/a',component:A,alias:'/b'
}]
})
可以理解为,路由/a和/b都是访问/a,只是url不同而已
9.导航守卫
a.前置守卫:beforeEach((to,from,next)=>{
//...
})
b.全局解析守卫:router.beforeResolve
c.全局后置钩子:router.afterEach((to,from)=>{})
d.路由独享的守卫:beforeEnter
e.组件内的守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
f.完整的导航解析流程:
>> 导航被触发
=> 在失活的组件里调用beforeRouteLeave守卫
=> 调用全局的beforeEach守卫
=> 在重用的组件里调用beforeRouteUpdate守卫
=> 在路由配置里调用beforeEnter
=> 解析异步路由组件
=> 在被激活的组件里调用beforeRouteEnter
=> 调用全局的beforeResolve守卫
=> 导航被确认
=> 调用全局的afterEach钩子
=> 触发DOM更新
=> 调用beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入
10.数据获取,有时候,在进入某个路由的时候,需要从服务器获取初始化数据,比如用户信息等,我们可以通过两种方式获取:
a.导航完成之后获取:先完成导航,然后在组件的生命周期里获取数据
created(){
this.fetchData()
}
b.导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航
// 组件第一次渲染
beforeRouteEnter(to,from,next){
getList().then(res=>{
// 处理数据
next()
})
}
// 路由改变前,组件已经渲染完了
beforeRouteUpdate(to,from,next){
getList().then(res=>{
// 处理数据
next()
})
}
11.路由懒加载,通过把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载(有多轻松我还不知道,我还没了解懒加载的原理),只知道做法就是利用import把组件导入
const Foo = () => import('./Foo.vue')
12.导航故障是一个 Error 实例,附带了一些额外的属性。要检查一个错误是否来自于路由器,可以使用 isNavigationFailure 函数:
import VueRouter from 'vue-router'
const { isNavigationFailure, NavigationFailureType } = VueRouter
// 正在尝试访问 admin 页面
router.push('/admin').catch(failure => {
if (isNavigationFailure(failure, NavigationFailureType.redirected)) {
// 向用户显示一个小通知
showToast('Login in order to access the admin panel')
}
})
NavigationFailureType 可以帮助开发者来区分不同类型的导航故障。有四种不同的类型:
redirected:在导航守卫中调用了 next(newLocation) 重定向到了其他地方。
aborted:在导航守卫中调用了 next(false) 中断了本次导航。
cancelled:在当前导航还没有完成之前又有了一个新的导航。比如,在等待导航守卫的过程中又调用了 router.push。
duplicated:导航被阻止,因为我们已经在目标位置了