mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-06 16:16:42 +08:00
perf(app): throttle inactive realtime blur rendering (#511)
This commit is contained in:
+79
-1
@@ -26,6 +26,7 @@ import { configureApexChartsTheme } from '@/utils/apexCharts'
|
|||||||
|
|
||||||
const LOGIN_WALLPAPER_ROUTE = '/login'
|
const LOGIN_WALLPAPER_ROUTE = '/login'
|
||||||
const BACKGROUND_CROSSFADE_DURATION_MS = 1500
|
const BACKGROUND_CROSSFADE_DURATION_MS = 1500
|
||||||
|
const WINDOW_BLUR_RENDER_THROTTLE_DELAY_MS = 180_000
|
||||||
|
|
||||||
// 生效主题
|
// 生效主题
|
||||||
const vuetifyTheme = useTheme()
|
const vuetifyTheme = useTheme()
|
||||||
@@ -82,10 +83,12 @@ const shouldRenderGlobalBlurLayer = computed(
|
|||||||
transparentBackgroundBlur.value > 0 &&
|
transparentBackgroundBlur.value > 0 &&
|
||||||
transparencyGlassQuality.value === 'realtime',
|
transparencyGlassQuality.value === 'realtime',
|
||||||
)
|
)
|
||||||
|
const isRenderThrottled = ref(document.visibilityState === 'hidden')
|
||||||
let backgroundRetryTimer: number | null = null
|
let backgroundRetryTimer: number | null = null
|
||||||
let backgroundRequestController: AbortController | null = null
|
let backgroundRequestController: AbortController | null = null
|
||||||
let backgroundCrossfadeTimer: number | null = null
|
let backgroundCrossfadeTimer: number | null = null
|
||||||
let authenticatedStateTimer: number | null = null
|
let authenticatedStateTimer: number | null = null
|
||||||
|
let windowBlurRenderThrottleTimer: number | null = null
|
||||||
|
|
||||||
// 读取并同步透明主题背景设置到根组件响应式状态。
|
// 读取并同步透明主题背景设置到根组件响应式状态。
|
||||||
function applyTransparentBackgroundSettings() {
|
function applyTransparentBackgroundSettings() {
|
||||||
@@ -105,6 +108,52 @@ function handleTransparencySettingsChanged(event: Event) {
|
|||||||
|
|
||||||
applyTransparentBackgroundSettings()
|
applyTransparentBackgroundSettings()
|
||||||
|
|
||||||
|
function clearWindowBlurRenderThrottleTimer() {
|
||||||
|
if (windowBlurRenderThrottleTimer) {
|
||||||
|
window.clearTimeout(windowBlurRenderThrottleTimer)
|
||||||
|
windowBlurRenderThrottleTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreForegroundRendering() {
|
||||||
|
const wasRenderThrottled = isRenderThrottled.value
|
||||||
|
|
||||||
|
clearWindowBlurRenderThrottleTimer()
|
||||||
|
isRenderThrottled.value = false
|
||||||
|
|
||||||
|
if (wasRenderThrottled && backgroundImages.value.length > 1) {
|
||||||
|
startBackgroundRotation()
|
||||||
|
rotateBackgroundImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function throttleBackgroundRendering() {
|
||||||
|
clearWindowBlurRenderThrottleTimer()
|
||||||
|
resetBackgroundCrossfade()
|
||||||
|
isRenderThrottled.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWindowBlurRenderThrottle() {
|
||||||
|
clearWindowBlurRenderThrottleTimer()
|
||||||
|
if (document.visibilityState === 'hidden') {
|
||||||
|
throttleBackgroundRendering()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
windowBlurRenderThrottleTimer = window.setTimeout(() => {
|
||||||
|
if (document.visibilityState === 'visible' && !document.hasFocus()) {
|
||||||
|
isRenderThrottled.value = true
|
||||||
|
}
|
||||||
|
windowBlurRenderThrottleTimer = null
|
||||||
|
}, WINDOW_BLUR_RENDER_THROTTLE_DELAY_MS)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWindowFocusRenderThrottle() {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
restoreForegroundRendering()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 心跳检测
|
// 心跳检测
|
||||||
let heartbeatInterval: number | null = null
|
let heartbeatInterval: number | null = null
|
||||||
let prefersColorSchemeMediaQuery: MediaQueryList | null = null
|
let prefersColorSchemeMediaQuery: MediaQueryList | null = null
|
||||||
@@ -177,12 +226,18 @@ function handleSystemThemeChange() {
|
|||||||
// 页面重新可见时同步主题,修复后台期间设置被外部修改后的外观漂移。
|
// 页面重新可见时同步主题,修复后台期间设置被外部修改后的外观漂移。
|
||||||
function handleVisibilityThemeSync() {
|
function handleVisibilityThemeSync() {
|
||||||
if (document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
|
restoreForegroundRendering()
|
||||||
syncThemePreferenceFromStorage()
|
syncThemePreferenceFromStorage()
|
||||||
|
} else {
|
||||||
|
throttleBackgroundRendering()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面从缓存或重新聚焦恢复时刷新主题偏好。
|
// 页面从缓存或重新聚焦恢复时刷新主题偏好。
|
||||||
function handlePageShowThemeSync() {
|
function handlePageShowThemeSync() {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
restoreForegroundRendering()
|
||||||
|
}
|
||||||
syncThemePreferenceFromStorage()
|
syncThemePreferenceFromStorage()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,6 +285,8 @@ async function fetchBackgroundImages() {
|
|||||||
|
|
||||||
// 背景图片轮换函数
|
// 背景图片轮换函数
|
||||||
function rotateBackgroundImage() {
|
function rotateBackgroundImage() {
|
||||||
|
if (isRenderThrottled.value) return
|
||||||
|
|
||||||
if (backgroundImages.value.length > 1) {
|
if (backgroundImages.value.length > 1) {
|
||||||
// 计算下一个图片索引
|
// 计算下一个图片索引
|
||||||
const nextIndex = (activeImageIndex.value + 1) % backgroundImages.value.length
|
const nextIndex = (activeImageIndex.value + 1) % backgroundImages.value.length
|
||||||
@@ -414,6 +471,8 @@ onMounted(async () => {
|
|||||||
document.addEventListener('visibilitychange', handleVisibilityThemeSync)
|
document.addEventListener('visibilitychange', handleVisibilityThemeSync)
|
||||||
window.addEventListener('pageshow', handlePageShowThemeSync)
|
window.addEventListener('pageshow', handlePageShowThemeSync)
|
||||||
window.addEventListener('focus', handlePageShowThemeSync)
|
window.addEventListener('focus', handlePageShowThemeSync)
|
||||||
|
window.addEventListener('focus', handleWindowFocusRenderThrottle)
|
||||||
|
window.addEventListener('blur', handleWindowBlurRenderThrottle)
|
||||||
window.addEventListener(TRANSPARENCY_SETTINGS_CHANGED_EVENT, handleTransparencySettingsChanged)
|
window.addEventListener(TRANSPARENCY_SETTINGS_CHANGED_EVENT, handleTransparencySettingsChanged)
|
||||||
|
|
||||||
// 登录页壁纸仅在未登录登录页需要,避免其他首屏额外发起图片列表请求。
|
// 登录页壁纸仅在未登录登录页需要,避免其他首屏额外发起图片列表请求。
|
||||||
@@ -461,6 +520,7 @@ onUnmounted(() => {
|
|||||||
window.clearTimeout(authenticatedStateTimer)
|
window.clearTimeout(authenticatedStateTimer)
|
||||||
authenticatedStateTimer = null
|
authenticatedStateTimer = null
|
||||||
}
|
}
|
||||||
|
clearWindowBlurRenderThrottleTimer()
|
||||||
// 停止心跳
|
// 停止心跳
|
||||||
stopHeartbeat()
|
stopHeartbeat()
|
||||||
prefersColorSchemeMediaQuery?.removeEventListener('change', handleSystemThemeChange)
|
prefersColorSchemeMediaQuery?.removeEventListener('change', handleSystemThemeChange)
|
||||||
@@ -468,12 +528,14 @@ onUnmounted(() => {
|
|||||||
document.removeEventListener('visibilitychange', handleVisibilityThemeSync)
|
document.removeEventListener('visibilitychange', handleVisibilityThemeSync)
|
||||||
window.removeEventListener('pageshow', handlePageShowThemeSync)
|
window.removeEventListener('pageshow', handlePageShowThemeSync)
|
||||||
window.removeEventListener('focus', handlePageShowThemeSync)
|
window.removeEventListener('focus', handlePageShowThemeSync)
|
||||||
|
window.removeEventListener('focus', handleWindowFocusRenderThrottle)
|
||||||
|
window.removeEventListener('blur', handleWindowBlurRenderThrottle)
|
||||||
window.removeEventListener(TRANSPARENCY_SETTINGS_CHANGED_EVENT, handleTransparencySettingsChanged)
|
window.removeEventListener(TRANSPARENCY_SETTINGS_CHANGED_EVENT, handleTransparencySettingsChanged)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="app-wrapper">
|
<div class="app-wrapper" :class="{ 'app-wrapper--render-throttled': isRenderThrottled }">
|
||||||
<!-- 透明主题背景 -->
|
<!-- 透明主题背景 -->
|
||||||
<div
|
<div
|
||||||
v-if="backgroundImages.length > 0 && (isTransparentTheme || !isLogin)"
|
v-if="backgroundImages.length > 0 && (isTransparentTheme || !isLogin)"
|
||||||
@@ -584,6 +646,22 @@ onUnmounted(() => {
|
|||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-wrapper--render-throttled {
|
||||||
|
.global-blur-layer {
|
||||||
|
backdrop-filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-bg-decor *,
|
||||||
|
.login-logo,
|
||||||
|
.login-logo-wrapper,
|
||||||
|
.login-logo-wrapper::before,
|
||||||
|
.login-title,
|
||||||
|
.login-subtitle,
|
||||||
|
.agent-assistant-fab * {
|
||||||
|
animation-play-state: paused !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 登录页壁纸在 VApp 外层渲染,登录页 VApp 需要透明才能露出壁纸。 */
|
/* 登录页壁纸在 VApp 外层渲染,登录页 VApp 需要透明才能露出壁纸。 */
|
||||||
.app-shell--login-wallpaper.v-application {
|
.app-shell--login-wallpaper.v-application {
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
|
|||||||
Reference in New Issue
Block a user