1.动态路由匹配
(1)在一个组件中需要不同的用户来渲染这个组件,例如我们有个usercenter,需要根据不同id来渲染
usercenter,这样我们就可以使用动态路由来匹配
const = new Router({
routes:[
{
path: '/usercenter/:uid',
component: usercenter
}
]
})
路由参数一般通过 :来定义它,但路由匹配成功时,参数会被设置到 this.$route.params,
这样我们就可以在组件中使用了
const userCenter = {
template: '<div>{{$route.params.uid}}</div>',
}
这里我们有两个动态参数 /usercenter/0 导航到 /usercenter/1,
原来的组件就会被复用,但是不会触发钩子函数。
重新创建也可,但复用明显更高效。这里官方提供两个参考:
//其一:
//每次改变路由$route对象就会更新相应参数
const userCenter = {
template: '...',
watch:{
$route(to,from) {
//在这里执行响应路由变化的操作
}
}
}
//其二:
//通过组件间的导航守卫
cosnt = userCenter = {
template: '...',
beforeRouteUpdate(to,from,next) {
//在这里执行响应路由变化的操作
}
}
捕获所有 404 not Found
如果想匹配任意路径 ,这里用* 通配符来匹配,这里要注意的是匹配顺序。
{
path: '*'
},
{
path: '/usercenter-*'
}
当使用通配符时,$route.params会自动添加一个pathMatch的参数。它会包含通配符匹配的部分。
//给一个{path: '*' ...}
this.$router.push('/notfound')
this.$route.params.pathMatch // notfound
//给一个{path: '/usercenter-*'}
this.$router.push('/usercenter-admin')
this.$route.params.pathMatch // admin
所有路由按顺序匹配,谁先定义谁的,谁优先级就高
2.路由嵌套
项目中最顶层都会有一个路由出口标签,同样的一个组件中也可以有自己的子路由出口
称为路由嵌套,需要在父路由属性中设置children。
new Router({
routes[
{
path: '/tabs',
component: Tabs,
children:[
{
path: 'home',
component: Home
}
]
}
]
})
chileren 就像是routes数组一样配置。所以你可以嵌套多个路由。
在父路由设置出口标签
const tabs = {
template: '
<h1>this is tabs</h1>
<router-view></router-view>
'
}
这样就可以使用 /tabs/home 来访问该路由了。 基于以上的配置此时访问 /tabs
是访问不到的,这是因为没有匹配的子路由。可以使用如下方法:
{
path: '/tabs',
component: Tabs,
[
{
path: '',
component: Home
}
]
}
3.编程式导航
除了通过来创建a标签定义导航链接,
还可以通过router实例,来编写代码来实现导航。
在Vue实例内部,可以通过 r o u t e r 访 问 路 由 , 通 过 p u s h 方 法 , 来 实 现 编 程 导 航 t h i s . router访问路由,通过push方法,来实现编程导航 this. router访问路由,通过push方法,来实现编程导航this.router.push() 。
r o u t e r . p u s h , 会 向 h i s t o r y 添 加 一 个 新 记 录 , 当 用 户 点 击 浏 览 器 后 退 按 钮 时 , 则 回 到 之 前 的 U R L 。 当 使 用 < r o u t e r − l i n k t o = " " > 会 在 内 部 调 用 router.push,会向history添加 一个新记录,当用户点击浏览器后退按钮时, 则回到之前的URL。 当使用<router-link to="">会在内部调用 router.push,会向history添加一个新记录,当用户点击浏览器后退按钮时,则回到之前的URL。当使用<router−linkto="">会在内部调用router.push()方法,
所以点击等同与调用$router.push()
router.push()
//字符串
const uid = 10
this.$router.push(`/list/${uid}`); // => /list/10
<router-link to="/list/10"></router-link> // => /list/10
//对象
this.$router.push({path: '/list/10'}) // => /list/10
this.$router.push({path: '/list',params: { uid } }) // => /list
this.$router.push({name: 'list', params: { uid } }) // => /list/10
this.$router.push({path: `/list/${uid}`,query:{uid: uid}}) // => /list/10?uid=12
这里需要注意的是: 使用path 会忽略name 属性 在 router-link :to="{}"标签中规则如上。
router.replace()
这里还提供一个方法 r o u t e r . r e p l a c e ( ) , 他 的 使 用 方 法 与 router.replace(),他的使用方法与 router.replace(),他的使用方法与router.push() 无异。
唯一不同的是他不会向history添加新记录,而是替换掉当前的history记录。router.to()
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步。
router.go(1) //前进一步
router.go(-1) //后退
4.路由重定向和别名
1.重定向
重定向是通过routes配置完成的,下面还是看tabs的实例
new Router({
routes:[
{
path:'/tabs'
component: Tabs,
children:[
{
path:'home',
component: Home
},
{ ... },
]
}
]
})
以上父路由tabs,子路由home。要想访问子路由home。访问地址为/tabs/home。
我们要想进入/tabs时默认访问home组件。上面路由嵌套部分给出的是,子路由为空
children:[
{
path:'',
component: Home
}
]
这里我们使用重定向:
new Router({
routes:[
{
path:'/tabs'
component: Tabs,
redirect: '/tabs/home'
children:[
{
path:'home',
component: Home
}
]
}
]
})
我们直接输入地址 /tabs 会发现直接进入到 /tabs/home
以下有三种方式:
redirect:''
redirect:{name: ''}
redirect: to=>{
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}
2.别名
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,
那么“别名”又是什么呢?
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,
就像用户访问 /a 一样。
上面对应的路由配置为:
new Router({
routes:[
{
path:'/tabs'
component: Tabs,
children:[
{
path:'home',
component: Home,
alias:''
}
]
}
]
})
还是tabs的例子,这里我们给默认展示的子路由,起一个空别名,
当我们访问/tabs 就会匹配到home的别名。就会访问/tabs/home组件。
5.路由组件传参
使用$route会使其形成高度耦合,在指定的URL上使用,限制了其灵活性。
$route的耦合
var user = {
template:'<div>{{$route.params.id}}</div>'
}
var router = new Router({
routes:[
{
path:'/user/:id',
component: User
}
]
})
通过props解耦合
var user = {
props:[''id],
template:'<div>{{id}}</div>'
}
var router = new Router({
routes:[
{
path:'/user/:id',
component: User,
props:true
},
//对象包含命名视图的路由,你必须分名添加props
{
path:'/user/:id',
components:{
default:User,
sidebar: Sidebar
},
props:{
default: true,
sidebar: false
}
}
]
})
如果 props 被设置为 true,route.params 将会被设置为组件属性
6.导航守卫
‘导航’表示路由正在发生变化
**参数/查询字符的变化触发 进入/离开的导航守卫。可以通过$route的变化,或者beforeRouteUpdated
的组件内的守卫。
一、全局守卫
1、全局前置守卫
当一个导航触发时。全局前置守卫按照茶创建顺序调用 。守卫是异步解析执行的,
此时所有导航守卫resolve完之前一直处于等待中。
routre.beforeEach((to,from,next)=>{
})
每个守卫都接受三个参数:
to: Route :即将进入的目标路由
from: Route :当前导航要离开的路由
next: Function :一定要调用这个方法resolve这个钩子函数,
next() :确认执行。
next(false) :中断执行。
next(’/’)或者next({path: ‘/’}) :跳到一个不同的地址。
next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,
则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
确保要使用next方法,resolve。否则导航一直会处于等待状态。
2、全局解析守卫
注册全局解析钩子,router.beforeResolve(),这和rouer.beforeEach 类似。
区别是导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
router.beforeResolve((to,from,next)=>{
})
3、全局后置钩子
注册全局后置钩子,router.afterEach()和守卫不同的是,这些钩子不会接受next,也不会改变导航本身。
router.afterEach((to,from)=>{
})
二、路由独享守卫
可以在路由配置上直接定义 beforeEnter。
new Router({
routes:[
{
path:'/',
component: ...,
beforeEnter: (to,from,next)=>{
}
}
]
})
参数与全局前置守卫一样router.beforeEach
三、组件内的守卫
最后还可以在组件内直接使用路由导航守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const Foo = {
template: '...',
beforeRouteEnter(to,from,next) {
//在组件渲染被confirm前调用
// 这你 不能组件实例获取 this
//因为调用当前守卫时,组件实例还没有被创建
},
beforeRouteUpdate(to,from,next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to,from,next) {
//导航离开组件时调用
// 可以访问组件实例 `this`
}
}
1、beforeRouteEnter:
不能范围组件实例,因为在导航确认之前调用,组件还未被创建。
不过可以通next回调来访问组件实例。在导航被确认的时候执行回调。
并把组件实例作为回调参数
beforeRouteEnter(to,from,next){
next(vm=>{
//通过vm范围组件实例
})
}
注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。
对于 beforeRouteUpdate 和 beforeRouteLeave 来说,
this 已经可用了,所以不支持传递回调,因为没有必要了。
2、beforeRouteUpdate:
同一组件复用,并不会触发,生命周期。动态路由参数提到了,两中方法。
监听$route变化,和使用 beforeRouteUpdate。
beforeRouteUpdate(to,from,next){
this.name = to.params.name
next()
}
3、beforeRouteLeave:
这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
路由守卫一览:
//全局守卫
router.beforeEach((to,from,next)=>{
})
router.beforeResolve((to,from,next)=>{
})
router.afterEach((to,from)=>{
})
//局部守卫
new Router({
routes:[
{
path:'/any',
component:...,
beforEnter:((to,from,next)=>{
})
}
]
})
//组件守卫
beforeRouteEnter(to,from,next){
}
beforeRouteUpdate(to,from,next){
}
beforeRouteLeave(to,from,next){
}