From 5e50f9061bcf7aaa49d71ef821786459d1587332 Mon Sep 17 00:00:00 2001 From: hzj <1304805162@qq.com> Date: Fri, 15 May 2026 18:27:53 +0800 Subject: [PATCH] =?UTF-8?q?style(=E4=BD=8E=E7=AB=AF=E6=9C=BA=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F):=20=E5=B0=86=E5=9B=BE=E7=89=87=E7=9A=84=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E6=96=B9=E5=BC=8F=E8=AE=BE=E7=BD=AE=E6=88=90=E5=92=8C?= =?UTF-8?q?=E9=9D=9E=E4=BD=8E=E7=AB=AF=E6=9C=BA=E4=B8=80=E6=A0=B7=E4=BB=8E?= =?UTF-8?q?=E9=80=8F=E6=98=8E=E5=88=B0=E5=AE=8C=E5=85=A8=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/活动页/竞品H5与性能优化分析.md | 25 ++++++++++++++-- src/directives/smartImage.js | 46 +++++++++++++---------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/docs/活动页/竞品H5与性能优化分析.md b/docs/活动页/竞品H5与性能优化分析.md index 13f2126..6744168 100644 --- a/docs/活动页/竞品H5与性能优化分析.md +++ b/docs/活动页/竞品H5与性能优化分析.md @@ -226,7 +226,7 @@ cacheLimits: { `useCanvas` 入参暂时保留,避免大量历史页面需要同步改模板;后续新页面不再依赖它做防扒取。 -### 8. `v-smart-img` 低端机关闭淡入动画 +### 8. `v-smart-img` 低端机图片显示策略 修改文件: @@ -238,7 +238,20 @@ cacheLimits: { el.decoding = 'async' ``` -这样可以减少图片加载时的主线程和合成压力。 +同时,所有 `v-smart-img` 图片都会在缓存解析和真实图片加载完成前先隐藏: + +```js +el.style.opacity = '0' +el.style.transition = skipFade ? 'none' : 'opacity 0.3s ease-in-out' +``` + +加载成功后再统一显示: + +```js +el.style.opacity = '1' +``` + +这样可以避免低端机上先出现浏览器失败占位图,再替换成真实图片的问题。低端机仍然使用 `transition: none`,不会恢复淡入动画,不会增加持续合成成本;只是一次性隐藏、一次性显示。 ### 9. 全局低端机移除高成本模糊,滚动动画保持可用 @@ -255,7 +268,13 @@ backdrop-filter 低端机模式和系统“减少动态效果”模式都不再暂停 `.scroll-wrapper` 这类跑马灯动画,避免 iOS 或低端安卓上排行榜、奖励列表、用户昵称等文本滚动完全不动。系统开启“减少动态效果”时,只暂停弹幕这类更重的装饰动画。 -同时,多个活动页和榜单页的 `isLoading` 预加载阶段已取消渲染 `BackgroundLayer`、背景图片和其他装饰节点,只保留 `LoadingSpinner` 和 loading 文案。两者统一包在 `.loading-content` 容器中,使用半透明黑底、8px 圆角和 10px 内边距,避免加载态和正式页面重复创建背景图层。 +同时,全项目带 `loading-container` 的预加载阶段已取消渲染 `BackgroundLayer`、背景图片和其他装饰节点,只保留 `LoadingContent`。`LoadingContent` 内部统一包在 `.loading-content` 容器中,使用半透明黑底、8px 圆角和 10px 内边距,避免加载态和正式页面重复创建背景图层。 + +补充调整: + +- `src/views/Invitation/InviteToRegister.vue` 和 `src/views/Invitation/inviteNewUser.vue` 的加载态移除 `BackgroundLayer`。 +- `src/views/Activities/DailyRecharge/index.vue` 主内容改为 `v-else`,避免加载态期间提前挂载背景图和 VAP。 +- `src/views/CPReward/index.vue` 主内容由 `v-show="!isLoading"` 改为 `v-else`,避免加载态期间提前创建图片列表。 ### 10. 弹幕组件专项优化 diff --git a/src/directives/smartImage.js b/src/directives/smartImage.js index d6c8378..827383c 100644 --- a/src/directives/smartImage.js +++ b/src/directives/smartImage.js @@ -9,23 +9,17 @@ export const smartImage = { el.decoding = 'async' - if (!skipFade) { - el.style.opacity = '0' - el.style.transition = 'opacity 0.3s ease-in-out' - } - const url = getValidUrl(binding.value, el) if (url) { - await processImage(el, url, skipFade) + prepareImageLoadingState(el, skipFade) + await processImage(el, url) el._smartImageCurrentUrl = url el._smartImageOriginalBindingValue = binding.value return } - if (!skipFade) { - el.style.opacity = '1' - } + showImage(el) }, async updated(el, binding) { @@ -39,11 +33,8 @@ export const smartImage = { } if (currentUrl && currentUrl !== el._smartImageCurrentUrl) { - if (!skipFade) { - el.style.opacity = '0' - } - - await processImage(el, currentUrl, skipFade) + prepareImageLoadingState(el, skipFade) + await processImage(el, currentUrl) el._smartImageCurrentUrl = currentUrl el._smartImageOriginalBindingValue = binding.value } @@ -77,7 +68,17 @@ function getValidUrl(bindingValue, el) { return null } -async function processImage(el, url, skipFade = false) { +function prepareImageLoadingState(el, skipFade) { + // 低端机也要先隐藏待处理图片,避免缓存异步完成前出现浏览器失败占位。 + el.style.opacity = '0' + el.style.transition = skipFade ? 'none' : 'opacity 0.3s ease-in-out' +} + +function showImage(el) { + el.style.opacity = '1' +} + +async function processImage(el, url) { if (!url) { return } @@ -89,25 +90,23 @@ async function processImage(el, url, skipFade = false) { const imageUrl = await imageCacheManager.scheduleRequest(resolvedUrl) const handleLoad = () => { - if (!skipFade) { - el.style.opacity = '1' - } + showImage(el) el.removeEventListener('load', handleLoad) } + el.removeEventListener('load', el._smartImageLoadHandler) el.addEventListener('load', handleLoad) el._smartImageLoadHandler = handleLoad const handleError = (error) => { console.error('Image load failed:', resolvedUrl, error) - if (!skipFade) { - el.style.opacity = '1' - } + showImage(el) el.removeEventListener('error', handleError) } + el.removeEventListener('error', el._smartImageErrorHandler) el.addEventListener('error', handleError) el._smartImageErrorHandler = handleError el.src = imageUrl @@ -115,9 +114,6 @@ async function processImage(el, url, skipFade = false) { const fallbackUrl = resolveProtectedAssetUrl(url) console.warn(`Image processing failed: ${fallbackUrl}`, error) el.src = fallbackUrl - - if (!skipFade) { - el.style.opacity = '1' - } + showImage(el) } }