1 keep-alive业务场景使用
问题:
在k页面根据pageNum请求到该分页的数据进行展示,pageNum的值假设此时为3,去到a页面,点击匹配其他条件又到k页面,此时因为k页面被keep-alive保存状态,有数据缓存,所以显示的还是pageNum=3的分页数据造成页面显示异常;
试过把pageNum初始化为1的方法,但是当数据量过大时,会先显示数据异常的页面,然后才显示初始化为1的分页数据;
需求:
a→k→b→a→k即离开k页面后只要从a页面点击跳转到k页面时,不使用缓存数据,数据应该更新(要注意如果是原来的匹配条件时,缓存需要保存);
解决方法:
第一种(成功解决)
在a页面路由跳转需要携带的参数里添加添加一个初始化变量initial=true决定是否初始化;
在k页面的activated钩子里获取路由的参数,然后用一个变量接即initial2=initial || false
然后if(initial2) {
pageNum = 1 //初始化
}
k页面(即分情况刷新或缓存数据的页面)
a页面(点击a页面不同地方携带不同的参数请求不同的数据在k页面显示)
k页面
data() {
return {
initialization: true,
}
}
async activated() {
console.log("进入到activated");
this.queryForm=this.$route.query;
this.initialization=this.queryForm.initialization||false;
console.log(this.totalQuantityProblem.initialization);
if(this.initialization){
console.log("数据初始化");
this.page.pageNum = 1;
this.totalQuantityProblem.type=this.queryForm.type||'';
this.totalQuantityProblem.status=Number(this.queryForm.status);
await this.getData();
await this.getMinus();
}
},
a页面
methods: {
goProblemDetail(data) {
this.$router.push({
path: "/allProblemHome",
query: {
type:data.type,
status:data.status||0,
initialization:true,
},
})
},
}
第二种(没被采用)
在路由种设置keepAlive属性结合在组件使用v-if判断是否需要缓存
{
path: 'list',
name: 'itemList',
meta: {
keepAlive: true,
title: '列表页'
}
}
因为项目组件太多业务逻辑复杂,最开始时没有使用这个控制是否缓存,所以该方法没采用。
第三种(比较复杂,没被采用—大概的思路)
用 keep-alive 提供的 include 和 exclude ,然后配合vuex实现动态控制。
app.vue
<keep-alive :include='includes' :exclude='':max="3">
<router-view></router-view>
</keep-alive>
其中include代表着要缓存的,exclude代表着非缓存的,max代表最多缓存的个数。
// 获取vuex的数据
import {mapGetters} from 'vuex'
export default {
computed: {// 在computed中动态监控
...mapGetters(['includes']),
},
methods: {
changeStore() {
// 改变vue的数据,在这用不到
this.$store.commit('change', 'tableLists')
}
}
}
vuex
const keepalive = {
state: {
includes: ['tableLists']
},
mutations: {
change(state, payload) {
state.includes = payload
},
},
getters: {
includes(state) {
return state.includes
}
}
};
export default keepalive
2 原理
参考文章:
keep-alive原理分析(有源码分析)
2.1 keep-alive是什么?
是vue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM;
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们;
可以设置以下props属性:
● include - 字符串或正则表达式。只有名称匹配的组件会被缓存;
● exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存;
● max - 数字。最多可以缓存多少组件实例
使用include和exclude的注意点:
● 每个组件内部添加 {name:xx}
● 若将include设置空 ’ ’ 每个页面都将会缓存
● exclude的优先级高于include 使用exclude后
关于keep-alive的基本用法
<keep-alive>
<component :is="view"></component>
</keep-alive>
使用includes和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>
2.2 include和exclude无效问题
使用include/exclude 属性需要给所有vue类的name赋值(注意不是给route的name赋值),否则 include/exclude不生效
export default {
name:'TableList', // include 或 exclude所使用的name
data () {
return {}
},
}
设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activated与deactivated):
● 首次进入组件时:beforeRouteEnter > beforeCreate > created> mounted > activated > … … > beforeRouteLeave > deactivated
● 再次进入组件时:beforeRouteEnter >activated > … … > beforeRouteLeave > deactivated
2.3 缓存后如何获取数据
解决方案可以有以下两种:
● beforeRouteEnter
● actived
beforeRouteEnter
每次组件渲染的时候,都会执行beforeRouteEnter
beforeRouteEnter(to, from, next){
next(vm=>{
console.log(vm)
// 每次进入路由执行
vm.getData() // 获取数据
})
},
actived
在keep-alive缓存的组件被激活的时候,都会执行actived钩子
activated(){
this.getData() // 获取数据
},
注意:服务器端渲染期间avtived不被调用
2.4 联系
HTTP和TCP中的keep-alive和KeepAlive
● HTTP协议(七层)的Keep-Alive意图在于连接复用,希望可以短时间内在同一个连接上进行多次请求/响应。核心在于:时间要短,速度要快。
● TCP协议(四层)的KeepAlive机制意图在于保活、心跳,检测连接错误。核心在于:虽然频率低,但是持久。
(当一个TCP连接两端长时间没有数据传输时(通常默认配置是2小时),发送keepalive探针,探测链接是否存活。)
可看文章:
HTTP中的keep-alive—1
HTTP中的keep-alive—2
HTTP中的keep-alive—3