定义路由的时候可以配置 meta 字段:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
首先,我们称呼 routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录。
例如,根据上面的路由配置,/foo/bar 这个 URL 将会匹配父路由记录以及子路由记录。
一个路由匹配到的所有路由记录会暴露为 $route 对象(还有在导航守卫中的路由对象)的 $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 的所有功能 在这里同样适用。
1. 单个路由的过渡
上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用 并设置不同的 name。
const Foo = {
template: `
<transition name="slide">
<div class="foo">...</div>
</transition>
`
}
const Bar = {
template: `
<transition name="fade">
<div class="bar">...</div>
</transition>
`
}
2. 基于路由的动态过渡
还可以基于当前路由与目标路由的变化关系,动态设置过渡效果:
<!-- 使用动态的 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'
}
}
在开发中,我们遇到这样的一个常见的的场景,从主页 跳转到 列表页 跳转到 详情页,详情页 返回 列表页 返回 首页。我们希望,从 详情页 返回 列表页 的时候页面的状态是缓存,不用重新请求数据,提升用户体验。从 列表页 返回 主页 的时候页面,注销掉列表页,以在进入不同的列表页的时候,获取最新的数据。
上述的按需加载的场景可以使用之前提到过的keep-alive
标签实现:
keep-alive
接收三个参数:
include
:可传字符串、正则表达式、数组
,名称匹配成功的组件(组件名称)会被缓存exclude
:可传字符串、正则表达式、数组
,名称匹配成功的组件不会被缓存max
:可传数字
,限制缓存组件的最大数量
include
和exclude
,传数组
情况居多
直接将路由占位符放进去就行了
<keep-alive :include="allowList" :exclude="noAllowList" :max="amount">
<router-view></router-view>
</keep-alive>
动态路由实现
(1)在Router
里定义好需要缓存的视图组件
new Router({
routes: [
{
path: '/',
name: 'index',
component: () => import('./views/keep-alive/index.vue'),
meta: {
deepth: 0.5
}
},
{
path: '/list',
name: 'list',
component: () => import('./views/keep-alive/list.vue'),
meta: {
deepth: 1
keepAlive: true //需要被缓存
}
},
{
path: '/detail',
name: 'detail',
component: () => import('./views/keep-alive/detail.vue'),
meta: {
deepth: 2
}
}
]
})
(2)写2个router-view
出口
<keep-alive :include="include">
<!-- 需要缓存的视图组件 -->
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
(3)在 app.vue 里监听路由的变化
export default {
name: "app",
data: () => ({
include: []
}),
watch: {
$route(to, from) {
//如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 include数组
if (to.meta.keepAlive) {
!this.include.includes(to.name) && this.include.push(to.name);
}
//如果 要 form(离开) 的页面是 keepAlive缓存的,
//再根据 deepth 来判断是前进还是后退
//如果是后退
if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
var index = this.include.indexOf(from.name);
index !== -1 && this.include.splice(index, 1);
}
}
}
};
代码中的 push
和 splice
的是 router
的 name
。建议把 route
的 name
属性设置和 route
对应component
的name
设成一样的。