需求
项目中有3个页面,首页A,信息列表页B,信息详情页C:
B => C, C=> B 希望回到B页面时,页面和跳转到C时一样(主要指数据)
B与其他页面相互跳转时,是重新加载B页面
这是keep-alive标签典型的应用场景,缓存组件
要点
- 在渲染页面B的router-view处(demo 中是App.vue处)增加加上父标签 keep-alive
<keep-alive :include="keepAliveComponents">
<router-view></router-view>
</keep-alive>
属性include,支持字符串、正则、数组,只有组件名称能匹配上的时候才会缓存。
如果什么属性都不添加,则会缓存所有组件。注意:如果是include是空字符串,也会缓存所有组件
2. 在定义router的地方给需要缓存的组件添加标记,同时增加路由守卫,将需要缓存的组件名称添加到数组中。
let router = new VueRouter({
mode: 'history',
routes: [{
path: '/', //?openDialog=true pc端
name: 'home',
component: Home,
meta: {
module: 'my'
}
},{
path: '/site/ranking/:type', //排行榜 week, month, total
name: 'ranking',
component: Ranking,
meta: {
module: 'ranking',
keepAlive: true,
componentName: 'ranking' // 文中的B页面
}
}, ......
]
});
router.beforeEach((to, from, next) => {
// 作用是每次进入组件时,判断是否需要混存
if (to.meta.keepAlive) {
// 作用是向App.vue中的数组keepAliveComponents push数据(不存在此名称时才push)
// 也可以用vuex
StateManage.addComponent(to.meta.componentName)
}
next();
});
B页面是有条件的缓存,当它离开跳转的目标页面不是C页面时,不需要缓存
export default{
name: 'ranking', // 一定要写
data(){
return{......}
},
beforeRouteLeave (to, from, next) {
// 如果下一个页面不是客人态页面,则取消缓存
if (to.name !== 'guest') {
// 作用是从App.vue组件中的数组keepAliveComponents删除组件名称
StateManage.deleteComponent('ranking');
}
next();
}
}
3. 小问题
如果网站中页面一开始加载的页面就是B页面时需要注意:router的路由守卫是在App.vue 组件的created事件之前,请确保路由守卫在这种情况下也能正确修改在App.vue中的数据。
因为我这里使用StateManage修改,是通过App.vue中监听事件(如下)。路由守卫中的emit事件(调用方法StateManage.addComponent)发生在监听之前,不会修改数据,所以这种情况需要单独处理一下。
(可能用vuex不会有这样的问题,没用过)
created(){
// 路由守卫在created 之前,如果初始页面也需要keepalive 单独处理一下
if(this.$route.meta.keepAlive){
this.keepAliveComponents = [this.$route.meta.componentName];
}
// StateBus是一个vue对象,用来做全局的状态管理,项目不太,没有使用vuex
// StateManage方法调用StateBus对象emit事件
StateBus.$on('add-component', (name) => {
if(this.keepAliveComponents.indexOf(name) === -1){
this.keepAliveComponents.push(name);
}
});
.....
}
其他
页面跳转之后再跳转回来,希望保持页面中数据不变,还可以将页面数据相关的条件写在路由中。比如列表页面,将分页数据和筛选条件放在url的query部分。这样在浏览器中前进后退,或者将url发给别人时也能保持页面数据一致。