vue-router文档细读

Vue-Router

在组件内,可以通过 this. router访this. r o u t e r 访 问 路 由 器 , 通 过 t h i s . route 访问当前路由

当 对应的路由匹配成功,将自动设置 class 属性值 .router-link-active

1. 动态路由匹配

通过设置路由的 path 为 /user/:id 的这种形式,此时可以通过在组件内使用 this.$router.params.id 来进行接收参数 id 。这里设置多段路由路径参数也是可行的 /user/:username/post/:post_id

像这种路由参数的变化,并不会引起组件的销毁重新创建,而是被复用。这就意味着组件的生命周期钩子函数不会被调用。想要监测,我们可以通过使用 watch 来进行。

watch: {
    '$route' (to, from) {
        ...do someting
    }
}

或者使用导航守卫

beforeRouteUpdate (to, from, next) {
    ... do someting
}

关于匹配的优先级,同一个路径可以匹配多个路由。优先级就按照路由定义的顺序:谁先定义、谁的优先级就高

2. 嵌套路由

主要通过 VueRouter 的参数中使用 children 配置来进行嵌套

3. 编程式的导航

this.$router.push(location, onComplete, onAbort):导航到不同的 URL,这个方法会向 history 栈添加一个新的记录,等同于 <router-link :to="...">

this.$router.push({naem: 'user', params: {userId: 123}})

// 带上查询参数,就必须使用 path,但是使用 path 会自动忽略 params
this.$router.push({path: 'user', query: {plan: 'a'}})

let userId = 123
this.$router.push({path: `/user/${userId}`})  // -> /user/123

router.replacerouter.push 中提供了 onCompleteonAbort 回调作为第二个和第三个参数。这些回调会在导航成功完成(在所有的异步钩子被解析之后),或终止(导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由)的时候进行相应的调用

注意:如果目的地和当前路由相同,只有参数发生了变化(如从 /user/1 到 /user/2),这时候需要使用 beforeRouteUpdate 来响应这个变化

this.router.replace(location, onComplete, onAbort),和 router.push 相似,不过他不会向 history 添加新的记录,而是替换掉当前的 history 记录
声明式:<router-link :to="..." replace>

this.$router.go(n) 参数是一个整数,代表在 history 记录中向前或者向后退多少步,如果 history 记录不够用,则会默默的失败

4. 命名路由

在创建路由实例的时候,通过在 routes 配置中给某个路由设置名称:name: '...'

这时就可以通过:<router-link :to="{name: 'user', params: {userId: 123}}">,这个和使用 router.push() 是一回事

5. 命名视图

显示方式:

// 这里没有进行 name 命名的路由,是默认出口
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>

在 router 实例中的创建:

routes: [
    {
        path: '/',
        components: {
            default: Foo,
            a: Bar,
            b: Laz
        }
    }
]

6. 重定向和别名

同样可以通过 routes 配置来完成

routes: [
    { path: '/a', redirect: '/b' }
]

// 重定向的目标可以使一个命名的路由
routes: [
    { path: '/a', redirect: { name: 'foo' } }
]

// 设置可以使一个方法,动态返回重定向的目标
routes: [
    { path: '/a', redirect: to => {
        // 方法接受 目标路由 作为参数
        // return 重定向的 字符串路径 / 路径对象
    } }
]

别名:

// 访问 /b 是,URL会保持为 /b,但是路由匹配为 /a
routes: [
    routes: [
        { path: '/a', component: A, alias: '/b' }
    ]
]

7. 路由组件传参

使用 props 将组件和路由解耦,取代与 $route 的耦合
“`
routes: [
{
path: ‘/user/:id’
component: User,
props: true
}
]

// 之后在 User 组件内,可以通过设置 props 来进行接收
const User = {
props: [‘id’],
template: <div>{{ id }}</div>
}


// 对于包含命名视图的路由,必须要分别为每个命名视图添加 props 选项
routes: [
{
path: ‘/user/:id’,
components: {
default: User,
sidebar: Sidebar
},
props: {
default: true,
sidebar: false
}
}
]
“`

使用 props 的好处:可以在任何地方使用该组件,使得组件更易于重用和测试

props 被设置成相应的数据类型
1. 布尔模式:props 设置为 true,route.params 将会被设置为组件属性
2. 对象模式:会被按原样设置为组件属性,当 props 是静态的时候有用
3. 函数模式:可以创建一个函数返回 props。这样可以将参数转换成另一种类型,将静态值与基于路由的值结合等等

尽可能保持 props 函数为无状态的,因为它只会在路由繁盛变化时起作用,如果需要状态来定义 props。则使用包装组件,这样 Vue 才可以对状态变化做出反应

进阶

1. 导航守卫

主要通过跳转或取消的方式守卫导航,有多种机会植入路由导航过程中:全局的,单个路由独享的,或者组件级的

注意:参数或者查询的改变并不会触发进入 / 离开的导航守卫,可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫

全局守卫

可以使用 router.beforeEach 注册一个全局前置守卫

const router = new VueRouter({...})
router.beforeEach((to, from, next) => {
    // ...
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行的,此时导航在所有守卫 resolve 完之前一直处于等待中
每个守卫方法接受三个参数:
- to:即将要进入的目标路由对象
- from:当前导航正要离开的路由
- next:一定要调用这个方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数

关于 next:
- next():进入下一个钩子,如果全部钩子执行完了,则导航的状态是 comfirmed (确认的)
- next(false):中断当前的导航,如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址
- next(‘/’) 或者 next( {path: ‘/’ }):跳转到一个不同的地址。当前的导航被中断,然后进行新的导航
- next(error):如果参数是一个 Error 实例,则导航会终止且该错误会被传递给 router.onError() 注册过的回调

注意:一定要确保调用 next 方法,否则钩子就不会被 resolved

全局解析守卫

可以使用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似。区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用

全局后置钩子

这个钩子并不会改变导航本身,也不接收 next 函数

router.afterEach((to, from) => {
    // ...
})

路由独享的守卫

可以直接在路由配置上定义 beforeEnter 守卫

routes: [
    {
        path: '/foo',
        component: Foo,
        beforeEnter: (to, from, next) => {
            // ...
        }
    }
]

组件内的守卫

  • beforeRouteEnter(to, from, next):渲染该组件的对应路由被 confirm 前调用,无法获取 this,且组件的实例还没有创建
  • beforeRouteUpdate(to, from, next):当前路由改变,但是该组件被复用时调用,可以访问 this
  • beforeRouteLeave(to, from, next):导航离开该组件时调用,可以访问 this

beforeRouteEnter 虽然不能访问 this,但是可以通过 next 来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数

beforeRouteEnter (to, from, next) {
    next (vm => {
        // 通过 vm 访问组件实例
    })
}

注意:beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUptate 和 beforeRouteLeave 来说,this 已经可用,所以不支持传递回调,没有必要

至于离开守卫 beforeRouteLeave 通常用来禁止用户在还未保存前提前离开。该导航可以通过 next(false) 来取消

完整的导航解析流程
1. 导航被触发
2. 在失活的组件里调用离开守卫
3. 调用全局的 beforeEnter 守卫
4. 在重用的组件里调用 beforeRouteUpdate 守卫
5. 在路由配置里调用 beforeEnter
6. 解析异步路由组件
7. 在被激活的组件里调用 beforeRouteEnter
8. 调用全局的 beforeResolve 守卫
9. 导航被确认
10. 调用全局的 afterEach 钩子
11. 触发 DOM 更新
12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数

2. 路由元信息

定义路由时可以配置 meta 字段:

routes: [
    {
        path: '/foo',
        component: Foo,
        chilren: [
            {
                path: 'bar',
                component: Bar,
                meta: { requiresAuth: true }
            }
        ]
    }
]

routes 配置中的每个路由对象为‘路由记录’,路由记录是可以嵌套的。因此当一个路由匹配成功时,他可能匹配了多个路由记录
/foo/bar 这个 URL 会匹配父路由记录和子路由记录
一个路由匹配到的所有路由记录会暴露为 route r o u t e 对 象 ( 还 有 在 导 航 守 卫 中 的 路 由 对 象 ) 的 route.matched 数组。因此我们需要遍历 $route,matched 来检查路由记录中的 meta 字段

3. 过渡动效

<router-view>是基本的动态组件,所以我们可以用 transition> 件给他添加一些过渡效果

<transition>
    <router-view></router-view>
</transition>

单个路由的过渡

如果想让每个路由组件有各自的过渡效果,可以在各路由组件内使用 <transition> 并设置不同的 name

cosnt Foo = {
    template: `
        <transition name="slide">
            <div class="foo">...</div>
        </transition>
    `
}

基于路由的动态过渡

可以基于当前路由与目标路由的变化关系,动态设置过渡效果

<transition :name="transitionName">
    <router-view></router-view>
</transition>
// 在父组件内,通过 watch $route 决定使用哪种过渡
watch: {
    '$route' (to, from) {
        // do someting
        this.transitionName = isActice ? 'slide-right' : 'slide-left'
    }
}

4. 数据获取

渲染页面需要从服务器获取用户的数据,这里主要可以通过两种方式来实现
- 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示
- 导航完成之前获取:导航完成之前,在路由进入的守卫中获取数据,在数据获取成功后执行导航(获取数据时,用户会停留在当前的界面)

5. 滚动行为

这个功能只在支持 history.pushState 的浏览器中可用
在 Router 实例中,提供了一个 scrollBehavior 方法

const router = new VueRouter({
    routes: [...],
    scrollBehavior (ro, from, savedPosition) {
        // return 期望滚动到哪个位置
    }
})

这里的第三个参数 savedPosition 当且仅当 popstate 导航(通过浏览器的 前进 / 后退 按钮触发)时才可用,具体展示:

{x: number, y: number}
{selector: string, offset? : {x: number, y: number}}
// 如果返回的是一个 falsy 的值,或者空对象,那么不会发生滚动行为
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值