Vue-Router进阶
路由元信息
定义路由的时候可以配置meta字段:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
那么如何访问这个meta字段呢?
首先,我们称呼routes配置中的每个路由对象为路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录。
例如,根据上面的路由配置,/foo/bar这个URL将会匹配父路由记录以及子路由记录。
一个路由匹配到的所有路由记录会暴露为route.matched数组。因此,我们需要遍历$route.matched来检查路由记录中的meta字段。
下面例子展示在全局导航守卫中检查元字段:
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()
}
})
路由元信息,主要针对路由跳转时对匹配到的路由执行一些操作。
过渡动效
<router-view>是基本的动态组件,所以我们可以用<transition>组件给它添加一些过渡效果:
<transition>
<router-view></router-view>
</transition>
单个路由的过渡
上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用<transition>并设置不同的name。
<transition name="fade">
<user-agent></user-agent>
</transition>
基于路由的动态过渡
还可以基于当前路由与目标路由的变化关系,动态设置过渡效果:
<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'
}
}
滚动行为
使用前端路由,当切换到新路由时,想要页面滚动到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。vue-router能做好,而且更好,它让你可以自定义路由切换时页面如何滚动。
注意:这个功能只在支持history.pushState的浏览器中可用。
当创建一个Router实例,你可以提供一个scrollBehavior方法:
const router = new VueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
}
})
scrollBehavior方法接收to和from路由对象。第三个参数savedPosition当且仅当popstate导航(通过浏览器的前进/后退按钮触发)时才可用。
这个方法返回滚动位置的对象信息,例如:
- { x: number, y: number }
- { selector: string, offset ? : { x: number, y: number } }
如果返回一个falsy的值或者是一个空对象,那么不会发生滚动。
举例:
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
对于所有路由导航,简单地让页面滚动到顶部。
返回savedPosition,在按下后退/前进按钮时,就会像浏览器的原生表现那样:
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
如果你要模拟"滚动到锚点"的行为:
scrollBehavior (to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash
}
}
}
异步滚动
你可以返回一个Promise来得出预期的位置描述:
scrollBehavior (to, from, savedPosition) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ x: 0, y: 0 })
}, 500)
})
}
将其挂载到从页面级别的过渡组件的事件上,令其滚动行为和页面过渡一起良好运行是可能的。但是考虑到用例的多样性和复杂性,我们仅提供这个原始的接口,以支持不同用户场景的具体实现。
路由懒加载
当打包构建应用时,JavaScript包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
首先,可以将异步组件定义为返回一个Promise的工厂函数(该函数返回的Promise应该resolve组件本身):
const Foo = () => Promise.resolve({/*组件定义对象*/})
第二,在Webpack2中,我们可以使用动态import语法定义代码分块点:
import('../Foo.vue') // 这个 `import` 函数会返回一个 `Promise` 对象。
结合这两者,这就是如何定义一个能够被Webpack自动代码分割的异步组件。
const Foo = () => import ('../Foo.vue')
在路由配置中什么都不需要改变,只需要像往常一样使用Foo:
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
把组件按组分块
有时候我们想把某个路由下的所有组件都打包在同个异步块(chunk)中。只需要使用命名chunk,一个特殊的注释语法来提供chunk name。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。