当我们使用Vue来回切换页面,并希望保持页面组件状态的时候,会用到Vue的keep-alive
抽象组件。以下为官网中的说明:
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和
相似,
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
这里注意,必须包裹动态组件时,缓存机制才会生效
下面为简单的使用方式:
<keep-alive>
<router-view :key="key"></router-view>
</keep-alive>
这里的key
属性,我使用的是当前组件的完整路径。
computed:{
key(){
return this.$route.fullPath;
}
}
之后,每次切换路由,之前组件的状态在返回时会被保存起来。
当然,如果功能上只需保存指定组件状态,而不是所有组件状态,可以在keep-alive
标签内加上include
或exclude
属性。
他们分别接受三种类型的值:
<keep-alive include="account">
<router-view :key="key"></router-view>
</keep-alive>
上面的account
必须与子组件的name
选项保持一致
<keep-alive :include="['account','comment']">
<router-view :key="key"></router-view>
</keep-alive>
<keep-alive :include="/account|comment/">
<router-view :key="key"></router-view>
</keep-alive>
使用数组或正则筛选组件时,属性include
必须使用v-bind
修饰符。
此外,exclude
的优先级大于include
,看下面的例子:
<keep-alive :include="/account|comment/" :exclude="/account/">
<router-view :key="key"></router-view>
</keep-alive>
例子中,使用正则表达式,分别缓存account
与comment
组件状态,并设定不缓存account
组件状态,执行后的效果为,页面切换回comment
时,状态保持,而account
被设定为了初始状态,没有保存之前的输入内容。
在实践中遇到的问题
当页面包含多个使用同一个组件渲染的区域时,由于组件的name属性相同,keep-alive不能缓存指定的区域,可以通过设定Vue-Router来解决这个问题。看以下代码:
export default new Router({
mode: "history",
routes: [//路由匹配规则
{ path: "/", redirect: '/account/login' },//重定向到redirect指定的位置
{
path: "/account", component: accountInfo,
redirect: "/account/login", children: [
{ path: "login", component: login },
{ path: "register", component: register },
]
},//path:路由指定url地址,component指定匹配好的组件
{ path: "/comment2", component: comment, meta: { keepAlive: true } },
{ path: "/comment3", component: comment},
{ path: "/comment4", component: comment, meta: { keepAlive: false } }
],
linkActiveClass: 'activeNav'
})
以上Vue-Router设定中,给路径/comment2
添加meta: { keepAlive : true}
选项来指定只缓存此路由所显示组件的状态。接着在App.vue的template
中添加以下代码:
<div style="position:relative">
<transition mode="out-in">
<keep-alive>
<router-view :key="key" v-if="$route.meta.keepAlive" style="position:absolute;width:100%"></router-view>
</keep-alive>
</transition>
<transition mode="out-in">
<router-view :key="key" v-if="!$route.meta.keepAlive" style="position:absolute;width:100%"></router-view>
</transition>
</div>
这样,页面中切换组件时,需要缓存的组件状态就会被保留了。
上述使用传统的v-if
方式,加入两个router-view
,此时就如果组件间存在过度动画,就会遇到过渡动画显示异常的问题,即如果组件在同一组transition
中切换时,过度动画显示正常,而当切换不同transition
时,过度动画会重叠。我的解决方案是修改:
原先在没有使用两个transition
时,过度动画全局样式我是这么写的:
.v-enter-active,
.v-leave-active {
transition: all 0.6s ease;
}
参考官网的过度动画生命周期后,现在改为:
.v-enter-active{
transition: all 0.6s ease;
transition-delay: 0.6s;
}
.v-leave-active{
transition: all 0.6s ease;
}
这样,我们让动画在进入前等待0.6秒后,开始进入状态,与动画离开的持续时间吻合后,就能做到与不加keep-alive
同样顺畅的动画效果了!