keep-alive 缓存
缓存的场景各种各样,稍微一改代码就大不相同。
所以我写的只是这一种场景:缓存一个页面(只是一个页面!),并且记录下这个页面的滚动位置。
必要的因素:
1.因为设置滚动是在router.js里scrollBehavior:设置的是 body滚动距离,所以这个页面不能有其他可以滚动的标签。
2.像mint-ui的上拉加载组件是父节点必须有overflow:hidden.所以也不能使用。
3.最好不要有tabbar,或者有的话在下面再加一个相等高度的div。要不然看不到最下面的东西。
用到的功能点:
1.记录滚动距离: window.addEventListener('scroll', this.handleScroll);
2.设置body滚动距离:router.js里scrollBehavior
3.记录缓存组件:app.vue:<keep-alive>
正式开始:
1.在app.vue文件:
<div id="app">
<!-- 缓存需要 -->
<keep-alive :max='1'>
<router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>
</div>
官网有keep-alive详细的解释-->传送门
我这里用到了max解释:max - 数字。最多可以缓存多少组件实例。
就是我上面提到的我只缓存一个实例
而$route.meta.keepAlive在router.js里设置
2.router.js:
{
path:'/index3',
name:'index3',
meta:{keepAlive:true},
component:() => import('./views/index3.vue')
},
3.这个时候就可以缓存页面了。接下来是保存页面滚动距离。
缓存页面它有自己的生命周期:
activated:组件激活时调用
deactivated:组件停用时调用。
每次进缓存页面时都要记录滚动距离,所以在 activated 里调用函数并且滚动距离及时保存在sessionStorage:
index3.vue :
mounted () {
window.addEventListener('scroll', this.handleScroll);
},
// 缓存组件的话,第二次是不走mounted的,
activated() {
window.addEventListener('scroll', this.handleScroll);
},
methods: {
handleScroll () {
let scrollY = window.scrollY
sessionStorage.setItem('height',JSON.stringify({h:scrollY}));
// console.log(scrollY,'scrollYindex333')
},
},
4.因为这个window.scrollY是全局的,所以在这个组件销毁时清除this.handleScroll
deactivated () {
window.removeEventListener('scroll', this.handleScroll)
}
5.记录页面滚动距离成功,这时候再进这个页面就要设置页面的滚动距离了,
在router.js里:
export default new Router({
routes:{
.......
},
scrollBehavior (to, from, savedPosition) {
// 从 A ----> B
// from to
// console.log(to,'to---------')
if (to.name === 'index3') {
// 拿到滚动距离!!!
let num = JSON.parse(sessionStorage.getItem('height'))
num = num ? num : 0
return { x: 0, y: num.h }
}
}
下面是index3的全部代码:
<template>
<div>
index3
<p>------分割线1---------</p>
<p>------分割线2---------</p>
<p>------分割线3---------</p>
<p>------分割线4---------</p>
<p>------分割线5---------</p>
<input type="text" style="height:60px;color:red">
<p>------分割线6---------</p>
<p>------分割线7---------</p>
<p>------分割线8---------</p>
<p>------分割线9---------</p>
<p>------分割线10---------</p>
<p>------分割线11---------</p>
<p>------分割线12---------</p>
<p>------分割线13---------</p>
<p>------分割线14---------</p>
<p>------分割线15---------</p>
<p>------分割线16---------</p>
<p>------分割线1---------</p>
<p>------分割线2---------</p>
<p>------分割线3---------</p>
<p>------分割线4---------</p>
<p>------分割线5---------</p>
</div>
</template>
<script>
export default {
name: 'index3',
data() {
return {}
},
methods: {
handleScroll () {
let scrollY = window.scrollY
sessionStorage.setItem('height',JSON.stringify({h:scrollY}));
// console.log(scrollY,'scrollYindex333')
},
},
// 及时地销毁
mounted () {
window.addEventListener('scroll', this.handleScroll);
},
destroyed () {
/* 加上keep-alive 则这个生命周期就不会走了。。。所以把清除放到deactivated */
},
// 缓存组件的话,第二次是不走mounted的,
activated() {
window.addEventListener('scroll', this.handleScroll);
},
deactivated () {
window.removeEventListener('scroll', this.handleScroll)
}
}
</script>
<style>
</style>
经历了一周的缓存组件较劲,以下是我的错误示范。
1>
其实很想动态清除缓存组件,只是现在还没有找到最好的解决方案。网上说的用this.$destroy()这种方法是不可行的,加上之后缓存页面不会再缓存,跟正常页面没有两样。不需要再试了。
2>
网上说的清除缓存使用this.$vnode.
我没有试成功,一周了。。太疲惫了。。。
首先我要缓存的组件是二级路由页面,压根打印不到 this.vnode.parent 是null。所以只能是一级路由页面parent才有值。并且我发现这个parent只有在从缓存组件跳到其他页面时才会有值。有兴趣的可以试试,这个还没有弄懂。
import Vue from 'vue'
/* Vue.mixin({
beforeRouteLeave(to, from, next) {
// 全局触发此事件
//下面是条件
if(to.name === 'regionalStatistics' && from.name === 'enterpriseQuery') {
if(this.$vnode.parent && this.$vnode.parent.componentInstance.cache) {
let key = this.$vnode.key == null
? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
: this.$vnode.key; // 当前关闭的组件名
let cache = this.$vnode.parent.componentInstance.cache // 缓存的组件
let keys = this.$vnode.parent.componentInstance.keys // 缓存的组件名
if(cache[key] != null) {
delete cache[key]
let index = keys.indexOf(key)
if(index > -1) {
keys.splice(index, 1)
}
}
}
}
next()
}
})
*/
3>
其实使用scrollBehavior 弊端是很大的,就是它设置的只能是body的滚动距离,还有另外一种方法:
使用@scroll 也可以监听元素滚动,并且记录下来。在页面渲染时再赋值于元素滚动距离。
@scroll可以肉眼看到滚动条滚动到指定位置,肯定没有scrollBehavior 效果好。
但是。。。我最后用了@scroll,我败在了mint-ui的上拉加载组件上。。
<div class='scrollList' @scroll="scroll">
------------------------------------------------------------------------------
/* 滚动 */
scroll() {
let height = document.getElementsByClassName('scrollList')[0].scrollTop
sessionStorage.setItem('TFD_HEIGHT',JSON.stringify({h:height}));
},
------------------------------------------------------------------------------
activated() {
setTimeout(() => {
let num = JSON.parse(sessionStorage.getItem('TFD_HEIGHT'))
document.getElementsByClassName('scrollList')[0].scrollTop = num.h
},100)
},
4>
chorme有一个插件 vue Devtools,其中有一个功能可以查看缓存组件,网上有很多安装的文章。
image.png
最后的最后,用了这么多纸只为了kepp-alive,还没有达到预期
image.png