From 693840d79d45979b68217aac1e4b504d78ebfbb8 Mon Sep 17 00:00:00 2001 From: AuroraHuang22 Date: Fri, 10 Jan 2025 11:38:14 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=88=20Enhance=20reading=20time=20track?= =?UTF-8?q?ing=20with=20tab=20focus=20pause?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/reader.vue | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/pages/reader.vue b/src/pages/reader.vue index d869a5f0e..1659b6b1f 100644 --- a/src/pages/reader.vue +++ b/src/pages/reader.vue @@ -46,8 +46,9 @@ export default { data() { return { isLoading: true, - openTimestamp: null, hasTrackedReaderClose: false, + activeTime: 0, + lastActiveTimestamp: null, }; }, head: { @@ -121,7 +122,7 @@ export default { }, }, async mounted() { - this.openTimestamp = Date.now(); + this.lastActiveTimestamp = Date.now(); try { this.isLoading = true; if (!this.classId) { @@ -167,32 +168,50 @@ export default { } finally { this.isLoading = false; } - window.addEventListener('beforeunload', this.handleBeforeUnload); - window.addEventListener('unload', this.handleBeforeUnload); + this.addEventListeners(); }, beforeDestroy() { - window.removeEventListener('beforeunload', this.handleBeforeUnload); - window.removeEventListener('unload', this.handleBeforeUnload); + this.trackReaderClose(); + this.removeEventListeners(); }, methods: { ...mapActions(['restoreAuthSession']), - handleBeforeUnload() { - this.trackReaderClose(); + addEventListeners() { + window.addEventListener('beforeunload', this.trackReaderClose); + window.addEventListener('unload', this.trackReaderClose); + document.addEventListener('visibilitychange', this.updateActiveTime); + }, + removeEventListeners() { + window.removeEventListener('beforeunload', this.trackReaderClose); + window.removeEventListener('unload', this.trackReaderClose); + document.removeEventListener('visibilitychange', this.updateActiveTime); }, trackReaderClose() { - if (this.hasTrackedReaderClose || !this.openTimestamp) return; + if (this.hasTrackedReaderClose) return; this.hasTrackedReaderClose = true; - const duration = Date.now() - this.openTimestamp; + this.updateActiveTime(); + + const durationInSeconds = Math.round(this.activeTime / 1000); logTrackerEvent( this, 'Reader', 'ReaderClose', this.classId, - Math.round(duration / 1000) + durationInSeconds ); }, + updateActiveTime() { + const now = Date.now(); + if (document.hidden && this.lastActiveTimestamp) { + const addedTime = Math.max(0, now - this.lastActiveTimestamp); + this.activeTime += addedTime; + this.lastActiveTimestamp = null; + } else if (!document.hidden) { + this.lastActiveTimestamp = now; + } + }, }, };