fix: resolve playroom UI state inconsistency when page loses focus
When lyrics are enabled and the page loses focus while playing a song without lyrics, then plays a song with lyrics, returning to the page caused controller and lyrics layout to become misaligned. Added page focus handlers to sync UI state correctly. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							parent
							
								
									ab5f021bf8
								
							
						
					
					
						commit
						92093ef80d
					
				| 
						 | 
				
			
			@ -543,8 +543,39 @@ watch(() => props.lrcSrc, async (newSrc) => {
 | 
			
		|||
	}
 | 
			
		||||
}, { immediate: true })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 页面焦点处理函数变量声明
 | 
			
		||||
let handleVisibilityChange: (() => void) | null = null
 | 
			
		||||
 | 
			
		||||
// 页面焦点处理
 | 
			
		||||
function setupPageFocusHandlers() {
 | 
			
		||||
	handleVisibilityChange = () => {
 | 
			
		||||
		if (document.hidden) {
 | 
			
		||||
			// 页面失去焦点时暂停动画
 | 
			
		||||
			if (scrollTween) scrollTween.pause()
 | 
			
		||||
			if (highlightTween) highlightTween.pause()
 | 
			
		||||
		} else {
 | 
			
		||||
			// 页面重新获得焦点时恢复并重新同步
 | 
			
		||||
			if (scrollTween && scrollTween.paused()) scrollTween.resume()
 | 
			
		||||
			if (highlightTween && highlightTween.paused()) highlightTween.resume()
 | 
			
		||||
			
 | 
			
		||||
			// 重新同步歌词位置
 | 
			
		||||
			nextTick(() => {
 | 
			
		||||
				if (currentLineIndex.value >= 0 && autoScroll.value && !userScrolling.value) {
 | 
			
		||||
					scrollToLine(currentLineIndex.value, false) // 不使用动画,直接定位
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	document.addEventListener('visibilitychange', handleVisibilityChange)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 组件挂载时的入场动画
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
	// 设置页面焦点处理
 | 
			
		||||
	setupPageFocusHandlers()
 | 
			
		||||
 | 
			
		||||
	// 控制面板入场动画
 | 
			
		||||
	if (controlPanel.value) {
 | 
			
		||||
		gsap.fromTo(controlPanel.value,
 | 
			
		||||
| 
						 | 
				
			
			@ -577,6 +608,11 @@ onUnmounted(() => {
 | 
			
		|||
	if (scrollTween) scrollTween.kill()
 | 
			
		||||
	if (highlightTween) highlightTween.kill()
 | 
			
		||||
	if (userScrollTimeout) clearTimeout(userScrollTimeout)
 | 
			
		||||
	
 | 
			
		||||
	// 清理页面焦点事件监听器
 | 
			
		||||
	if (handleVisibilityChange) {
 | 
			
		||||
		document.removeEventListener('visibilitychange', handleVisibilityChange)
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 暴露方法给父组件
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,6 +83,9 @@ onMounted(async () => {
 | 
			
		|||
	thumbUpdate()
 | 
			
		||||
 | 
			
		||||
	setupEntranceAnimations()
 | 
			
		||||
 | 
			
		||||
	// 添加页面焦点事件监听
 | 
			
		||||
	setupPageFocusHandlers()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
function timeFormatter(time: number) {
 | 
			
		||||
| 
						 | 
				
			
			@ -419,9 +422,98 @@ watch(() => [preferences.presentLyrics, getCurrentTrack()?.song.lyricUrl], (newV
 | 
			
		|||
	}
 | 
			
		||||
}, { immediate: true })
 | 
			
		||||
 | 
			
		||||
// 页面焦点处理函数变量声明
 | 
			
		||||
let handleVisibilityChange: (() => void) | null = null
 | 
			
		||||
let handlePageFocus: (() => void) | null = null
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
	// 清理页面焦点事件监听器
 | 
			
		||||
	if (handleVisibilityChange) {
 | 
			
		||||
		document.removeEventListener('visibilitychange', handleVisibilityChange)
 | 
			
		||||
	}
 | 
			
		||||
	if (handlePageFocus) {
 | 
			
		||||
		window.removeEventListener('focus', handlePageFocus)
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 页面焦点处理函数
 | 
			
		||||
function setupPageFocusHandlers() {
 | 
			
		||||
	handleVisibilityChange = () => {
 | 
			
		||||
		if (document.hidden) {
 | 
			
		||||
			// 页面失去焦点时,暂停所有动画
 | 
			
		||||
			console.log('[Playroom] 页面失去焦点,暂停动画')
 | 
			
		||||
		} else {
 | 
			
		||||
			// 页面重新获得焦点时,重新同步状态
 | 
			
		||||
			console.log('[Playroom] 页面重新获得焦点,同步状态')
 | 
			
		||||
			nextTick(() => {
 | 
			
		||||
				resyncLyricsState()
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handlePageFocus = () => {
 | 
			
		||||
		console.log('[Playroom] 窗口获得焦点,同步状态')
 | 
			
		||||
		nextTick(() => {
 | 
			
		||||
			resyncLyricsState()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 监听页面可见性变化
 | 
			
		||||
	document.addEventListener('visibilitychange', handleVisibilityChange)
 | 
			
		||||
	window.addEventListener('focus', handlePageFocus)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 重新同步歌词状态
 | 
			
		||||
function resyncLyricsState() {
 | 
			
		||||
	const currentTrack = getCurrentTrack()
 | 
			
		||||
	if (!currentTrack) return
 | 
			
		||||
 | 
			
		||||
	console.log('[Playroom] 重新同步歌词状态')
 | 
			
		||||
 | 
			
		||||
	// 重置动画状态
 | 
			
		||||
	if (controllerRef.value) {
 | 
			
		||||
		gsap.set(controllerRef.value, { 
 | 
			
		||||
			marginLeft: '0rem', 
 | 
			
		||||
			marginRight: '0rem' 
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lyricsSection.value) {
 | 
			
		||||
		gsap.set(lyricsSection.value, { 
 | 
			
		||||
			opacity: 1, 
 | 
			
		||||
			x: 0, 
 | 
			
		||||
			y: 0, 
 | 
			
		||||
			scale: 1 
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 检查当前歌词显示状态应该是什么
 | 
			
		||||
	const shouldShowLyrics = preferences.presentLyrics && currentTrack.song.lyricUrl ? true : false
 | 
			
		||||
 | 
			
		||||
	if (shouldShowLyrics !== presentLyrics.value) {
 | 
			
		||||
		console.log(`[Playroom] 歌词状态不一致,重新设置: ${presentLyrics.value} -> ${shouldShowLyrics}`)
 | 
			
		||||
		
 | 
			
		||||
		// 直接设置状态,不触发动画
 | 
			
		||||
		presentLyrics.value = shouldShowLyrics
 | 
			
		||||
		
 | 
			
		||||
		// 如果需要显示歌词,重新执行显示动画
 | 
			
		||||
		if (shouldShowLyrics) {
 | 
			
		||||
			nextTick(() => {
 | 
			
		||||
				const tl = gsap.timeline()
 | 
			
		||||
				tl.from(controllerRef.value, {
 | 
			
		||||
					marginRight: '-40rem',
 | 
			
		||||
					duration: 0.4,
 | 
			
		||||
					ease: "power2.out"
 | 
			
		||||
				}).fromTo(lyricsSection.value,
 | 
			
		||||
					{ opacity: 0, x: 50, scale: 0.95 },
 | 
			
		||||
					{ opacity: 1, x: 0, scale: 1, duration: 0.5, ease: "power2.out" },
 | 
			
		||||
					"-=0.2"
 | 
			
		||||
				)
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New: Watch for track changes and animate
 | 
			
		||||
watch(() => playQueueStore.currentIndex, () => {
 | 
			
		||||
	if (albumCover.value) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user