在开发中常常有从列表跳到详情页,而后返回详情页的时候须要缓存列表页的状态(好比滚动位置信息),这个时候就须要保存状态,要缓存状态;vue里提供了keep-alive组件用来缓存状态。
能够用如下几种方案解决问题;html
直接上代码,
一、首先在路由中的meta标签中记录keepAlive的属性为truevue
path: '/classify', name: 'classify', component: () => import('@/views/classify/classify.vue'), meta: { title: '雷石淘券券', keepAlive: true } },
二、在建立router实例的时候加上scrollBehavior方法正则表达式
export default new Router({ mode: 'history', base: process.env.BASE_URL, routes, scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition } else { return { x: 0, y: 0 } } } })
3/在须要缓存的router-view组件上包裹keep-alive组件vuex
<keep-alive> <router-view v-if='$route.meta.keepAlive'></router-view> </keep-alive><router-view v-if='!$route.meta.keepAlive'></router-view>
四、因为有些状况下须要缓存有些状况下不须要缓存,能够在缓存的组件里的路由钩子函数中作判断api
beforeRouteLeave (to, from, next) { this.loading = true if (to.path === '/goods_detail') { from.meta.keepAlive = true } else { from.meta.keepAlive = false // this.$destroy() } next() },
支持能够支持组件的缓存,可是这种方法有bug,首先第一次打开页面的时候并不缓存,即第一次从列表页跳到详情页,再回来并无缓存,后面在进入详情页才会被缓存
而且只会缓存第一次进入的状态,不会从新请求数据,若是当页面A选中一个分类跳到B页面,再从B列表页面跳往详情页,此时会缓存这个状态,而且之后再从A页面的其余分类跳到B页面都不会从新被缓存,以致于每次从详情页返回B页面都会跳第一次缓存的状态;当你的项目只有一种状态须要缓存,能够考虑使用这种方法数组
首先介绍一下include和exclude vue文档(https://cn.vuejs.org/v2/api/#...
是在vue2.0之后新增的属性
include是须要缓存的组件;
exclude是除了某些组件都缓存;
include 和 exclude 属性容许组件有条件地缓存。两者均可以用逗号分隔字符串、正则表达式或一个数组来表示:缓存
<!-- 逗号分隔字符串 --> <keep-alive include="a,b"> <component :is="view"></component> </keep-alive> <!-- 正则表达式 (使用 `v-bind`) --> <keep-alive :include="/a|b/"> <component :is="view"></component> </keep-alive> <!-- 数组 (使用 `v-bind`) --> <keep-alive :include="['a', 'b']"> <component :is="view"></component> </keep-alive>
匹配首先检查组件自身的 name 选项,若是 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。ide
max只在2.5.0新增,最多能够缓存多少组件实例。一旦这个数字达到了,在新实例被建立以前,已缓存组件中最久没有被访问的实例会被销毁掉。函数
<keep-alive :max="10"> <component :is="view"></component> </keep-alive>
简单介绍一下在被keep-alive包含的组件/路由中,会多出两个生命周期的钩子:activated 与 deactivated。
文档:在 2.2.0 及其更高版本中,activated 和 deactivated 将会在 树内的全部嵌套组件中触发。
activated在组件第一次渲染时会被调用,以后在每次缓存组件被激活时调用。
activated调用时机:
第一次进入缓存路由/组件,在mounted后面,beforeRouteEnter守卫传给 next 的回调函数以前调用:ui
beforeMount=> 若是你是从别的路由/组件进来(组件销毁destroyed/或离开缓存deactivated)=>mounted=> activated 进入缓存组件 => 执行 beforeRouteEnter回调
由于组件被缓存了,再次进入缓存路由/组件时,不会触发这些钩子:// beforeCreate created beforeMount mounted 都不会触发。
deactivated:组件被停用(离开路由)时调用
使用了keep-alive就不会调用beforeDestroy(组件销毁前钩子)和destroyed(组件销毁),由于组件没被销毁,被缓存起来了。
这个钩子能够看做beforeDestroy的替代,若是你缓存了组件,要在组件销毁的的时候作一些事情,你能够放在这个钩子里。
若是你离开了路由,会依次触发:
组件内的离开当前路由钩子beforeRouteLeave => 路由前置守卫 beforeEach =>全局后置钩子afterEach => deactivated 离开缓存组件 => activated 进入缓存组件(若是你进入的也是缓存路由
项目中缓存使用方法:
一、在建立的router对象上加scrollBehavior方法,同上;
二、将须要缓存的组件加在include属性里
<keep-alive :include="['home','classify','search']"> <router-view></router-view> </keep-alive>
三、在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里面的各类 } }) }
第三种方法和第二种类似,不一样的地方在于,将须要缓存的组件保存到全局变量,能够在路由的钩子函数里灵活的控制哪些组件须要缓存,那些不须要缓存;跟第二种方法相比,不须要每次再从新初始化数据,可是须要在vuex中保存数据;
上代码
一、在建立的router对象上加scrollBehavior方法,同上;
二、将须要缓存的组件加在include属性里
<keep-alive :include="catch_components"> <router-view></router-view> </keep-alive>
三、在store里加入须要缓存的的组件的变量名,和相应的方法;
export default new Vuex.Store({ state: { catch_components: [] }, mutations:{ GET_CATCHE_COMPONENTS (state, data) { state.catch_components = data } } })
三、在beforeRouteLeave钩子函数里控制须要缓存的组件
beforeRouteLeave (to, from, next) { //要在离开该组件的时候控制须要缓存的组件,不然将出现第一次不缓存的状况 this.busy = true if (to.path === '/goods_detail') { // 去往详情页的时候须要缓存组件,其余状况下不须要缓存 this.$store.commit('GET_CATCHE_COMPONENTS', ['home']) } else { this.$store.commit('GET_CATCHE_COMPONENTS', []) } next() },
以上是在vue项目里使用keep-alive的状况,网上有一些配合this.$destroy()方法使用的,但我在使用过程当中验证了,并很差用;若是有多个状态,而且有选择的缓存,那么第三个方法是最好的选择;若是你不想用vuex使用第二种方法也能够,但须要注意初始化数据。
另外,在咱们的项目中遇到路由相同但参数不一样的状况组件被复用,不更新的问题,vue官方给出了 响应路由参数变化
watch: { '$route' (to, from) { document.title = this.$route.query.name this.getDefault() //根据参数数据响应 } },