vue——keepAlive第一次无效问题及解决方法
搬运自:https://segmentfault.com/a/1190000019610283?utm_source=tag-newest
vue官方API: https://cn.vuejs.org/v2/api/#keep-alive
例:
router.js:
{
path: '/home',
name: 'Home',
meta: {
index: 0,
keepAlive: true,
title: '首页'
},
component: resolve => require(['../../../modules/Home'], resolve)
},
{ path: '/list', name: 'List', meta: { index: 1, keepAlive: true, title: '列表页' }, component: resolve => require(['../../../modules/List'], resolve) }, { path: '/detail', name: 'Detail', meta: { index: 2, keepAlive: false, title: '详情页' }, component: resolve => require(['../../../modules/Detail'], resolve) }
问题:列表页进详情页时,首先第一次打开页面的时候并不缓存,即第一次从列表页跳到详情页,再回来并没有缓存。后面再进入详情页才会被缓存,并且只会缓存第一次进入的状态,不会重新请求数据。如果当首页选中一个分类跳到列表页,再从列表页面跳往详情页,此时会缓存这个状态,并且以后再从首页的其他分类跳到列表页都不会重新被缓存,以至于每次从详情页返回列表页都会跳第一次缓存的状态。当你的项目只有一种状态需要缓存,可以考虑使用这种方法。
解决:使用 include + beforeRouteLeave 或者使用 include + beforeRouteLeave + vuex。
方法一:使用 include + beforeRouteLeave
1、在创建router实例的时候加上scrollBehavior方法
export default new Router({
routes,
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return {
x: 0,
y: 0
}
}
}
})
2、将需要缓存的组件加在include属性里
<keep-alive :include="['home','list','search']"> <router-view></router-view> </keep-alive>
3、在beforeRouteEnter的next回掉函数里,对返回A页面不需要缓存的的情况初始化,即将本来需要写在created里的东西写在这里;注意一定要将所有的需要初始化的数据要写一遍,不然会有bug;所以不太推荐
beforeRouteEnter (to, from, next) { next(vm => { // 通过 `vm` 访问组件实例 if (from.path !== '/goods_detail') { // 一定是从A进到B页面才刷新 vm.titleText = vm.$route.query.name vm.categoryUpper = vm.$route.query.categoryUpper vm.goods = [] vm.page = 1 vm.catsIndex = 0 vm.is_search = false vm.getCats2()// 是本来写在created里面的各种 } }) }
方法二:使用 include + beforeRouteLeave + vuex 与方法一相似,不同的地方在于,将需要缓存的组件保存到全局变量,可以在路由的钩子函数里灵活的控制哪些组件需要缓存,那些不需要缓存;跟方法一相比,不需要每次再重新初始化数据,但是需要在vuex中保存数据;
1、在创建router实例的时候加上scrollBehavior方法
export default new Router({ routes, scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition } else { return { x: 0, y: 0 } } } })
2、将需要缓存的组件加在include属性里
<keep-alive :include="catch_components"> <router-view></router-view> </keep-alive>
3、在store里加入需要缓存的的组件的变量名,和相应的方法;
export default new Vuex.Store({ state: { catch_components: [] }, mutations:{ GET_CATCHE_COMPONENTS (state, data) { state.catch_components = data } } })
4、在beforeRouteLeave钩子函数里控制需要缓存的组件
beforeRouteLeave (to, from, next) { //要在离开该组件的时候控制需要缓存的组件,否则将出现第一次不缓存的情况 this.busy = true if (to.path === '/goods_detail') { // 去往详情页的时候需要缓存组件,其他情况下不需要缓存 this.$store.commit('GET_CATCHE_COMPONENTS', ['home']) //注意,'home'将匹配首先检查组件自身的name
选项(非router.js里的),如果name
选项不可用,则匹配它的局部注册名称 (父组件components
选项的键值)。匿名组件不能被匹配。 } else { this.$store.commit('GET_CATCHE_COMPONENTS', []) } next()
}