vue2.x的路由2-进阶

本文参考网址:http://router.vuejs.org/zh-cn/


注意:vue-router是有明确的版本限制的。vue-router @2.x 只适用于 Vue 2.x 版本。



路由的进阶处理

 

(a)导航钩子

导航钩子主要用来拦截导航,让它完成跳转或取消。钩子是异步解析执行,此时导航在所有钩子 resolve 完之前一直处于 等待中

有多种方式可以在路由导航发生时执行钩子:全局的, 单个路由独享的, 或组件级的。

 

(a-1)全局导航钩子

Ø  before钩子:跳转之前执行

可以使用 router.beforeEach 注册一个全局的 before 钩子。当一个导航触发时,全局的 before 钩子按照创建顺序调用。

 

示例:

const router = new VueRouter({ ... });

router.beforeEach((to, from, next) => {

  // ...

})

-beforeEach参数说明:

l  to: Route: 即将要进入的目标 路由对象

l  from: Route: 当前导航正要离开的路由

l  next: Function,一定要调用next()方法,否则钩子就不会被 resolved了。执行效果依赖于 next ()的参数。调用效果如下:

next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

next(false):中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。

 

Ø  after 钩子:跳转之后执行

同样地,可以注册一个全局的 after 钩子,不过它不像 before 钩子那样,after 钩子没有 next 方法,不能改变导航。

示例:

router.afterEach(route => {

  //...

})

 

(a-2)单个路由独享的导航钩子

可以直接在路由配置上定义 beforeEnter 钩子:

示例:

const router = new VueRouter({

 routes: [

    {

     path: '/foo',

     component: Foo,

     beforeEnter: (to, from, next) => { //参数同上;

       // ...

     }

    }

  ]

})

 

 

(a-3)组件内的导航钩子

可以在路由组件内直接定义以下路由导航钩子:

l  beforeRouteEnter

l  beforeRouteUpdate (2.2 新增)

l  beforeRouteLeave

 

示例:

const Foo = {

 template: `...`,

 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` 访问组件实例

  })

}

 beforeRouteLeave 通常用来禁止用户在还未保存修改前突然离开。可以通过 next(false) 来取消导航。

 

 

(b)路由元信息—— 用来记录一些关键字段用于路由的精确匹配

由于路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录,可能会匹配父路由记录以及子路由记录。

一个路由匹配到的所有路由记录会暴露为 $route 对象(还有在导航钩子中的route 对象) $route.matched 数组

因此,我们需要遍历 $route.matched 来检查路由记录中的 meta 字段,从而确定更加匹配的路由记录

 

示例:

const router = new VueRouter({

 routes: [

    {

     path: '/foo',

     component: Foo,

     children: [

       {

         path: 'bar',

         component: Bar,         

         meta:{ requiresAuth: true }  // a metafield

       }

     ]

    }

  ]

})

 

router.beforeEach((to, from, next) => {

  if (to.matched.some(record => record.meta.requiresAuth)){

   // this route requires auth, check if logged in

   // if not, redirect to login page.

   if (!auth.loggedIn()) {

     next({

       path: '/login',

       query: { redirect: to.fullPath }

      })

    }else {

     next()

    }

  }else {

   next() // 确保一定要调用 next()

  }

})

 

(c)过渡效果

 

全局过渡效果:

<transition name=”fade”>

 <router-view></router-view>

</transition>

 

单个组件的过渡效果:

const Foo = {

 template: `

   <transition name="slide">

     <div class="foo">...</div>

   </transition>

  `

}

 

基于路由的动态过渡:

<!-- 使用动态的 transition name-->

<transition :name="transitionName">

 <router-view></router-view>

</transition>

 

// 接着在父组件内watch $route 从而决定使用哪种过渡

watch: {

 '$route' (to, from) {

   const toDepth = to.path.split('/').length

   const fromDepth = from.path.split('/').length

   this.transitionName = toDepth <fromDepth ? 'slide-right' : 'slide-left'

  }

}

 

(d)数据获取

有时候,进入某个路由后,需要从服务器获取数据。getPost()方法

可以通过两种方式来实现:

Ø  导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示『加载中』之类的指示。

Ø  导航完成之前获取:导航完成前,在路由的 enter 钩子中获取数据,在数据获取成功后执行导航。

 

航完成之后获取:

当你使用这种方式时,会马上导航和渲染组件,然后在组件的 created 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态。

示例:

<template>

 <div class="post">

   <div v-if="loading" class="loading">Loading...</div>

   <div v-if="error" class="error">{{ error}}</div>

   <div v-if="post" class="content">

     <h2>{{ post.title }}</h2>

     <p>{{ post.body }}</p>

   </div>

 </div>

</template>

 

export default {

 data () {

   return {

     loading: false,

     post: null,

     error: null

    }

  },

 created () {

   // 组件创建完后获取数据,此时 data 已经被 observed 了

   this.fetchData()

  },

 watch: {

   // 如果路由有变化,会再次执行该方法

   '$route': 'fetchData'

  },

 methods: {

   fetchData () {

     this.error = this.post = null;

     this.loading = true;

     // replace getPost with your data fetching util / API wrapper

     getPost(this.$route.params.id, (err, post) => {

       this.loading = false

       if (err) {

         this.error = err.toString()

       } else {

         this.post = post

       }

     })

    }

  }

}

 

航完成之前获取:

通过这种方式,我们在导航转入新的路由之前获取数据。我们可以在接下来的组件的 beforeRouteEnter 钩子中获取数据,当数据获取成功后只调用 next 方法。

 

在为后面的视图获取数据时,用户会停留在当前的界面,因此建议在数据获取期间,显示一些进度条或者别的指示。如果数据获取失败,同样有必要展示一些全局的错误提醒。

示例:

export default {

 data () {

   return {

     post: null,

     error: null

    }

  },

  beforeRouteEnter(to, from, next) {

    getPost(to.params.id, (err, post) =>

     if (err) {

       // display some global error message

       next(false)

     } else {

       next(vm => {

         vm.post = post

       })

     }

   })

  },

  // 路由改变前,组件就已经渲染完了

  // 逻辑稍稍不同

 watch: {

   $route () {

     this.post = null

     getPost(this.$route.params.id, (err, post) => {

       if (err) {

         this.error = err.toString()

       } else {

         this.post = post

       }

     })

    }

  }

}

 

 

(e)滚动行为

注意: 这个功能只在 HTML5 history 模式下可用。

当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置。

通过scrollBehavior 方法来设置滚动行为。这个方法返回滚动位置的对象信息,两种格式:

Ø  return { x: number, y: number }; //返回滚动的坐标位置

Ø  return { selector: string }; //返回滚动到的锚点

 

示例:

const router = new VueRouter({

 routes: [...],

  scrollBehavior (to, from, savedPosition) {

// return 期望滚动到哪个的位置

if (savedPosition) {

                       return savedPosition;      //保持当前位置;

                }else {

                       return { x: 0, y: 0 };   //返回顶部;

                } 

}

})

注释:参数解析:

to 和 from 为路由对象。

savedPosition :当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

 

scrollBehavior (to, from, savedPosition) {

  if(to.hash) {

   return { selector: to.hash };

  }

}

 

注释:还可以利用 路由元信息 更细颗粒度地控制滚动。请查看api文档。

 

 

(f)懒加载

当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

 

 

结合Vue  异步组件 和 Webpack  code splitting feature, 轻松实现路由组件的懒加载。

我们要做的就是把路由对应的组件定义成异步组件

 

const Foo = resolve => {

  //require.ensure 是 Webpack 的特殊语法,用来设置 code-split point代码分块;

 require.ensure(['./Foo.vue'], () => {

   resolve(require('./Foo.vue'))

  })

}

 

另一种代码分块的语法,使用 AMD 风格的 require,于是就更简单了。

const Foo = resolve => require(['./Foo.vue'],resolve)

const router = new VueRouter({

 routes: [

    {path: '/foo', component: Foo }

  ]

})

 

将组件按组分块

 

有时想把某个路由下的所有组件都打包在同个异步 chunk 中。只需要  chunk 命名,提供 require.ensure第三个参数(可选)作为chunk 的名称:

示例:

const Foo = r => require.ensure([], ()=> r(require('./Foo.vue')), 'group-foo')

const Bar = r => require.ensure([], ()=> r(require('./Bar.vue')), 'group-foo')

const Baz = r => require.ensure([], ()=> r(require('./Baz.vue')), 'group-foo')

Webpack 将相同 chunk 下的所有异步模块打包到一个异步块里面 —— 这也意味着我们无须明确列出 require.ensure的依赖(传空数组就行)。

 

 

更多关于vue-router的信息请查阅vue-router API文档。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值