也就是说,kee-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存 keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性。
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例
两个新的生命周期钩子
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。只适用于keep-alive
当组件在 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
activated :
路由组件被激活时触发。(当进入缓存的路由组件时触发)
使用 keep-alive 会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在 activated 阶段获取数据,承担原来 created 钩子函数中获取数据的任务
你应该初始读取一次数据,比如在created里面, 而activated第一次创建页面时不会激活,缓存之后,第二次进入才会开始激活
// 当缓存组件被激活的时候执行
activated(){ this.userName = this.$route.query.id },
deactivated:
路由组件失活时触发。(当离开缓存的路由组件时触发)
// 所有路径匹配到的视图组件都会被缓存!// 只缓存组件name为aa或者bb的组件 // 组件name为cc的组件不缓存 // 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存aa组件 // 如果缓存的组件超过了max设定的值3,那么将删除第一个缓存的组件
缺点:需要知道组件的 name,项目复杂的时候不是很好的选择
优点:不需要例举出需要被缓存组件名称
//在 router 目录下的 index.js 文件里 import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) import Layout from '@/layout' export default new Router = [ { path: '/admin', component: Layout, redirect: '/admin/user', alwaysShow: true, name: 'Admin', meta: { title: '系统管理', icon: 'documentation' }, children: [ { path: 'user', component: () => import('@/views/admin/user'), name: 'User', meta: { title: '用户管理', keepAlive: true // 需要缓存 } }, { path: 'user2', component: () => import('@/views/admin/user2'), name: 'User2', meta: { title: '用户管理2', keepAlive: false // 不需要缓存,默认不缓存,可以不写 } } ] } ]
App.vue
当然,也可以通过动态设置route.meta的keepAlive属性来实现其他需求,
首页是A页面
B页面跳转到A,A页面需要缓存
C页面跳转到A,A页面不需要被缓存
思路是在每个路由的beforeRouteLeave(to, from, next)钩子中设置to.meta.keepAlive:
A的路由
{ path: '/', name: 'A', component: A, meta: { keepAlive: true // 需要被缓存 } }
export default { data() { return {}; }, methods: {}, beforeRouteLeave(to, from, next) { // 设置下一个路由的 meta to.meta.keepAlive = true; // B 跳转到 A 时,让 A 缓存,即不刷新 next(); } };
export default { data() { return {}; }, methods: {}, beforeRouteLeave(to, from, next) { // 设置下一个路由的 meta to.meta.keepAlive = false; // C 跳转到 A 时让 A 不缓存,即刷新 next(); } };
所说的前进刷新后退不刷新是指组件是否重新渲染,比如列表list页面,点击其中的每一项进入详情detail页面,然后从detail页面后退到列表list页面时,list页面没有重新渲染,也没有重新发送ajax请求
routes: [{ path: '/', name: 'home', component: Home, meta: { keepAlive: false //此组件不需要被缓存 } }, { path: '/list', name: 'list', component: List, meta: { keepAlive: true //此组件需要被缓存 } }, { path: '/detail', name: 'detail', component: Detail, meta: { keepAlive: false // 此组件需要被缓存 } } ]
第一次进入keep-alive组件时,其生命周期执行顺序
beforeRouteEnter --> created --> mounted --> activated --> deactivated
非首次进入时,其生命周期执行顺序:
beforeRouteEnter -->activated --> deactivated
,非首次进入keep-alive组件时,正常的vue组件生命周期函数是不会在执行,而会执行keep-alive新增的两个周期钩子函数。同时也可以看出离开keep-alive组件时其destroy周期函数并没有执行,从侧面证明缓存组件并没有销毁。根据介绍,我们可以:
通过利用keep-alive提供activated钩子函数来决定是否进行ajax请求来更新组件,以及deactivated钩子函数来重置页面相关状态。
首先,在每个路由元信息meta中添加一个isBack字段
... { path: '/list', name: 'list', component: List, meta: { keepAlive: true, //此组件需要被缓存 isBack: false } } ...
(list.vue页面 )然后,借助beforeRouteEnter钩子函数来判断页面来源
beforeRouteEnter(to, from, next) { if(from.name === 'detail') { //判断是从哪个路由过来的,若是detail页面不需要刷新获取新数据,直接用之前缓存的数据即可 to.meta.isBack = true; } next(); },
最后,需要借助keep-alive提供钩子函数activated来完成是否更新:
activated() { if(!this.$route.meta.isBack) { // 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据 this.getData(); // ajax获取数据方法 } // 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据 this.$route.meta.isBack = false },
特殊情况,在keep-alive组件前进的页面刷新导致keep-alive组件状态丢失
继续以上面的list、detail页面为例,在进入详情页面后,然后刷新,这时列表页面的缓存的数据都丢失了,由于上面的判断规则也会导致不会重新获取数据。所以对于这种问题,还需要额外加一些判断条件。由于keep-alive第一次进入时会执行created方法,所以利用这点加一个标识来加以判断:
//第一次进入keep-alive路由组件时 created() { this.isFirstEnter = true; // 只有第一次进入或者刷新页面后才会执行此钩子函数,使用keep-alive后(2+次)进入不会再执行此钩子函数 },
activated() { if(!this.$route.meta.isBack || this.isFirstEnter){ // 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据 // 如果isFirstEnter是true,表明是第一次进入此页面或用户刷新了页面,需获取新数据 this.data = ''// 把数据清空,可以稍微避免让用户看到之前缓存的数据 this.getData(); } // 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据 this.$route.meta.isBack=false // 恢复成默认的false,避免isBack一直是true,导致每次都获取新数据 this.isFirstEnter=false; },
列表页回到上次浏览位置
条件:1、列表页不可使用懒加载延迟加载数据,2、列表页需要使用keepAlive缓存
beforeRouteLeave(to,from,next){ //离开页面之前将高度存储到sessionStorage。这里不建议用localStorage,因为session在关闭浏览器时会自动清除,而local则需要手动清除,有点麻烦。 sessionStorage.setItem('scrollH',document.getElementById('demo').scrollTop) next() },
activated(){ //在activated生命周期内,从sessionStorage中读取高度值并设置到dom if(sessionStorage.getItem('scrollH')){ document.getElementById('demo').scrollTop=sessionStorage.getItem('scrollH') } },
可使用ref
this.$refs.demo.scrollTop =50;
其他:
参考:
1路由缓存,
2前进后退刷新问题,
3.一直缓存,判断是否第一次进入,或者是否返回,返回重新请求数据刷新页面,不是的话默认缓存
上一篇:前端 Web 性能清单