Vue利用visibilitychange事件刷新数据,应对浏览
前言
在前端开发中,用户经常需要及时收到最新数据,根据紧急程度,有这样的方案:
-
实时获取数据:一般是通过WebSocket,比如股市动态,比如聊天,比如2台手机面对面互动,等等。
-
每次切回网页,要看到最新数据:这就用到今天说到的visibilitychange事件。
-
每隔固定时间获取新数据:定时器就搞定,不多说。
-
手动触发更新数据:这个不多说。
什么场景需要“切回网页,就刷新数据”?
现代浏览器对于机能优化都比较苛刻,比如我们做Vue开发的时候,你肯定要打开一个窗口预览,此时你再新建一个浏览器窗口,让原窗口成为后台窗口,接着,你再修改一下Vue项目代码,等几秒,然后让原窗口切回前台,你会发现预览页有跳动,也就是说,尽管原窗口已经收到了DOM修改,但是它只要在后台,就会憋着不改,直到原窗口转为前台,才会对DOM修改,于是就被你看见了修改过程。
这个节能机制听起来不错,但是也有坑,比如setInterval函数,这个定时器就不准了!因为它在后台的时候被挂起了!
另外,对于手机网页,这个问题就更严重了,手机对节能要求更甚,而且浏览器切到后台、锁屏都是极高概率事件!
有些数据无所谓,比如新闻列表,你不需要看到最新的新闻,你只需要在每天固定的时间点刷新下页面就好。但是,比如实时显示服务器时间,就必须要非常准确才行,这时候,我们就用visibilitychange事件好了。
环境
本次测试我用的HBuilderX的wap2app开发的APP,浏览器的话道理都是一样的。
wap2app本身支持显示和隐藏事件
是的,它从APP层级支持这两个事件,但是,这里(https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/12806)说的很清楚:
app.js里写的js代码,运行在本地一个独立的、不可见的Webview中(注意不是运行在首页Webview里)。
如果开发者要操作某个Webview里的dom,那么应该通过plus.webview的evalJS的api,给目标Webview注入一段js代码进行dom操作。
注入代码等于侵入代码,不如js原生开发舒服,所以,咱们还是用visibilitychange事件。
1. 变量docmentVisibility放到Vuex里
代码摘抄,假设我放在了app模块里:
docmentVisibility: false,
SET_DOCUMENT_VISIBILITY: (state, docmentVisibility) => {
state.docmentVisibility = docmentVisibility
},
2. 监听放到App.vue
created() {
document.addEventListener('visibilitychange', () => {
this.$store.commit('app/SET_DOCUMENT_VISIBILITY', document.hidden ? false : true);
});
}
3. 找到负责获取服务器时间的组件,改它
最终结果,hour负责保存时钟,minute保存分钟:
import timeApi from '@/api/system/time';
export default {
data() {
return {
timer: null,
hour: null,
minute: null,
};
},
computed: {
docmentVisibility() {
return this.$store.state.app.docmentVisibility;
},
},
watch: {
docmentVisibility(newVal) {
if (!newVal) return;
clearInterval(this.timer);
this.getServerTime();
},
},
created() {
this.getServerTime();
},
beforeDestroy() {
clearInterval(this.timer);
},
methods: {
calcTime(timestamp) {
this.hour = String(dayjs(timestamp).hour()).padStart(2, '0');
this.minute = String(dayjs(timestamp).minute()).padStart(2, '0');
},
getServerTime() {
timeApi.serverTimestamp().then((response) => {
let serverTimestamp = response.data;
this.calcTime(serverTimestamp);
this.timer = setInterval(() => {
serverTimestamp += 1000;
this.calcTime(serverTimestamp);
}, 1000);
});
},
},
};
总结
一些业务需要防范浏览器节能挂起,这时候就一定要利用visibilitychange事件刷新数据。