公司要求使用vue开发一款混合app,去年自学了一段时间,有前端给搭的框子,也上手体验了一次,中间遇到好多问题也都可以查资料解决,唯独这个vue的缓存界面功能一直没有好的方法,今年自己上手一个项目,实在受不了这坑爹的效果,所以着手研究研究,我现在使用的框架是我们前端搭的,我对前端也不是很了解,如有更好的思路请多多指教,我只是把我遇到的问题和解决方法写出来做个总结
问题
大家可以看到当重新进入列表页数据进行了刷新这明显不符合需求
如何解决
查百度问同事知道了一个东西叫keep-alive于是决定使用这个内置组件试试.
方案一
对所需要的组件添加keepAlive
{ path: '/messageList',
name: 'messageList',
meta: {
title: '消息列表',
keepAlive:true,
},
component: messageList
}
然后吧发现问题确实能够得到结局但是出了个新问题如图:
问题1:界面虽然被缓存但是当退出到前一个页面再进入的时候界面还是被缓存状态,我觉得这是不合理的.
问题2:被缓存的界面从上个页面再次进入时动画效果不对.
基于这两个问题我也查了一些资料和博客,也总结了第二套方案
方案二
思路:动态的改变keepAlive的值即在组件beforeRouteLeave中判断当页面离开的时候该进行缓存还是不缓存.这里给meta再增加一个rank(用啥字段都行)属性
{ path: '/messageList',
name: 'messageList',
meta: {
title: '消息列表',
rank: 1.5,
keepAlive:true,
},
component: messageList
}
这个rank是用来判断当前组件所在的级别.
比如A组件->B组件 ->C组件,那么A的rank为1,B的rank为2,C的rank为3,
在beforeRouteLeave中
beforeRouteLeave: function(to, from, next) {
if (to.meta.rank < from.meta.rank) {
from.meta.keepAlive = false;//这表示要到上一个界面把当前的keepAlive变为false
} else {
from.meta.keepAlive = true;//进入下一个界面需要缓存
}
next();
}
这个貌似能解决问题,但是!!!
问题1: 这个返回动画就是不对...(图片在浏览器可能看不出啥问题,在真机很明显)因为这个框架是前端给的动画我也不会弄...如果能解决跳转动画问题,我觉得这个方案基本可以符合要求..如果有大佬可以解决,方便的话指导下小弟.而且能解决这个动画问题后面也不用看了...
问题二:有的时候会出现缓存了上一次的bug(也不知道咋回事...出现的还挺频繁..).
说到这给大家推荐个博客,写的很详细奈何小弟能力有限看的不是太懂... (这是地址) 我试了半天没啥效果但给我的方案提供了很多好的思路.
方案三
在这里就是我自己总结的一个方案..虽然能完美解决这些问题不过对开发不友好,维护成本太高..不建议使用(如果实在没办法的话)
思路:放弃使用keepAlive,将需要进行缓存的界面(基本都需要)的数据使用vuex进行保存(还有界面的滑动高度.开始做的时候先弄的高度,后来发现可以把高度和数据写到一起,但赶时间就没有改).根据rank对界面进行判断,是加载缓存数据还是新数据,以达到所需要的效果.这个方法能完美解决问题.但比较难维护.
首先在vuex中定义需要缓存的界面的数据(先测试的滑动,所以分开写的可以只写一个data)
indexScrollTop: {
workList: 0, //首页待办滚动
}, //所有滚动界面滑动高度存储
listData: {
workList: {}, //首页待办数据
}, //所有滚动界面数据存储
先说下高度的滑动吧这个滑动的高度也是需要保存的.界面中沃使用cube-ui的scroll组件
<cube-scroll
ref="scroll"
:data="model.list"
:scroll-events="['scroll-end']"
:options="options"
@pulling-down="onPullingDown"
@pulling-up="onPullingUp"
@scroll-end="scrollend"
>
给data增加一个scrollHeight属性缓存界面高度.还有需要缓存的数据model
data() {
return :
model:{},
scrollHeight: 0, //记录滑动高度
},
当界面滑动停止调用scrollend方法对scrollHeight进行赋值
methods: {
scrollend(poy) {
this.scrollHeight = poy.y;
},
}
每次进入界面即在created 函数中取出缓存的高度,如果有高度那么让它自动滑动.并重新给scrollHeight进行赋值.
created() {
this.scrollHeight = this.scrollTool.getScrollTop(this, "workList");
},
这边是我封装的一个js..实现是这样的
function scrollTop(vc, title) {
var indexDic = vc.$store.getters.getIndexScrollTop;//取出组件缓存的高度
setTimeout(() => {
vc.$refs.scroll.scrollTo(0, indexDic[title], 0);//滑动到指定位置
}, 10);
return indexDic[title];
}
function setScrollTop(vm, title, height) {//保存缓存高度
var indexDic = vm.$store.getters.getIndexScrollTop;
indexDic[title] = height;
vm.$store.dispatch("setIndexScrollTop", indexDic);
}
var t = {
getScrollTop: function(vc, title) {
return scrollTop(vc, title)
},
setScrollTop: function(vm, title, height) {
return setScrollTop(vm, title, height)
}
}
export default t
这样就可以保证滑动的缓存(data与高度类似).
这是data的js
function getData(vc, title) {
var indexDic = vc.$store.getters.getListData;
return indexDic[title];
}
function setData(vm, title, data) {
var indexDic = vm.$store.getters.getListData;
indexDic[title] = data;
vm.$store.dispatch("setListData", indexDic);
}
var t = {
getData: function(vc, title) {
return getData(vc, title)
},
setData: function(vm, title, data) {
return setData(vm, title, data)
}
}
export default t
其实需要缓存的高度完全可以放到data中成为data的一个属性,当时因为特殊情况没有数据进行测试,所以先对所有界面进行高度缓存.做完发现完全写一个就可以...而且这些key也就是title.在定义的时候也可以直接使用组件的名称.这样在使用key的时候就可以直接用this.$route.name(复制起来更方便 哈哈....)
当界面进行跳转对组件的rank进行判断如下:
beforeRouteLeave: function(to, from, next) {
if (to.meta.rank < from.meta.rank) {//回退将数据清空
this.cacheData.setData(this, "workList", {});
this.scrollTool.setScrollTop(this, "workList", 0);
} else {//前进将数据缓存
this.cacheData.setData(this, "workList", this.model);
this.scrollTool.setScrollTop(this, "workList", this.scrollHeight);
}
next();
},
而在进入的时候
beforeRouteEnter(to, from, next) {
next(vm => {
if (to.meta.rank < from.meta.rank) {//如果从rank高的地方进入加载缓存数据
vm.model = vm.cacheData.getData(vm, "workList");
} else {//加载新数据
vm.toast.show();
vm.getData();
}
});
},