From a4884a689d9b3f5c39e3f26960afae17308067ba Mon Sep 17 00:00:00 2001 From: TerryM Date: Sat, 30 May 2026 01:54:28 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E5=9B=BE=E7=89=87=E6=B8=90=E8=BF=9B?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD,=E7=BC=A9=E7=9F=AD=E9=A6=96=E5=B1=8F?= =?UTF-8?q?=E7=AD=89=E5=BE=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 流内单图改用缩略图(原图仅在灯箱按需加载),体积大幅减小 - BubbleImage 加 decoding=async + 加载完淡入(ark-img-fade),图片逐张出现 - 视频海报/文件预览/推荐卡/热门榜补 decoding=async、lazy 原图无缩略图时自动回退,无回归。 Co-Authored-By: Claude Opus 4.8 (1M context) --- src/components/PopularRankList.tsx | 1 + src/components/RecommendedCard.tsx | 2 ++ src/components/messageStream/BubbleImage.tsx | 6 ++++- .../messageStream/bubbles/FileDocBubble.tsx | 1 + .../bubbles/SingleImageFrame.tsx | 5 +++++ .../messageStream/bubbles/VideoBubble.tsx | 22 +++++++------------ 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/components/PopularRankList.tsx b/src/components/PopularRankList.tsx index 3242e9f..f97cfed 100644 --- a/src/components/PopularRankList.tsx +++ b/src/components/PopularRankList.tsx @@ -136,6 +136,7 @@ function PopularRankRow({ src={cover} alt="" loading="lazy" + decoding="async" className="h-full w-full object-cover" onError={() => setCoverFailed(true)} /> diff --git a/src/components/RecommendedCard.tsx b/src/components/RecommendedCard.tsx index a56907a..ce8a857 100644 --- a/src/components/RecommendedCard.tsx +++ b/src/components/RecommendedCard.tsx @@ -116,6 +116,7 @@ export function RecommendedCard({ alt="" className="ark-img-fade h-full w-full object-cover transition duration-300 group-hover:scale-[1.02]" loading="lazy" + decoding="async" onLoad={(e) => e.currentTarget.classList.add("is-loaded")} /> ) : ( @@ -223,6 +224,7 @@ export function ComingSoonRecommendedCard({ alt="" className="h-full w-full object-cover opacity-75 grayscale-[15%]" loading="lazy" + decoding="async" /> 即将到来 diff --git a/src/components/messageStream/BubbleImage.tsx b/src/components/messageStream/BubbleImage.tsx index 342bc28..a109259 100644 --- a/src/components/messageStream/BubbleImage.tsx +++ b/src/components/messageStream/BubbleImage.tsx @@ -68,9 +68,13 @@ export function BubbleImage({ src={current} alt="" loading={loading} - className={className} + decoding="async" + className={`ark-img-fade ${className ?? ""}`} onLoad={(e) => { const img = e.currentTarget; + // Fade each image in as soon as it loads, so they appear progressively + // instead of the page seeming to wait for everything. + img.classList.add("is-loaded"); if (img.naturalWidth && img.naturalHeight) onNaturalSize?.(img.naturalWidth, img.naturalHeight); }} diff --git a/src/components/messageStream/bubbles/FileDocBubble.tsx b/src/components/messageStream/bubbles/FileDocBubble.tsx index 6b95078..4e5c2b8 100644 --- a/src/components/messageStream/bubbles/FileDocBubble.tsx +++ b/src/components/messageStream/bubbles/FileDocBubble.tsx @@ -45,6 +45,7 @@ function AttachmentRow({ postId, att }: { postId: string; att: Attachment }) { src={previewUrl} alt="" loading="lazy" + decoding="async" onError={() => setPreviewFailed(true)} className="h-16 w-16 shrink-0 rounded-lg object-cover" /> diff --git a/src/components/messageStream/bubbles/SingleImageFrame.tsx b/src/components/messageStream/bubbles/SingleImageFrame.tsx index be6a779..17d79e1 100644 --- a/src/components/messageStream/bubbles/SingleImageFrame.tsx +++ b/src/components/messageStream/bubbles/SingleImageFrame.tsx @@ -20,6 +20,11 @@ export function SingleImageFrame({ return ( openLightbox([attachment], 0, text, postId)} ariaLabel="View image" > diff --git a/src/components/messageStream/bubbles/VideoBubble.tsx b/src/components/messageStream/bubbles/VideoBubble.tsx index 1de9554..0771fa6 100644 --- a/src/components/messageStream/bubbles/VideoBubble.tsx +++ b/src/components/messageStream/bubbles/VideoBubble.tsx @@ -1,4 +1,4 @@ -import { LoaderCircle, Maximize2, Play, X } from "lucide-react"; +import { LoaderCircle, Play, X } from "lucide-react"; import { DownloadCloudIcon } from "../../icons/DownloadCloudIcon"; import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; @@ -79,10 +79,12 @@ function VideoAttachmentCard({ src={attachment.url} poster={attachment.posterUrl} controls + controlsList="nodownload noplaybackrate noremoteplayback" + disablePictureInPicture playsInline autoPlay onClick={(e) => e.stopPropagation()} - className="absolute inset-0 h-full w-full" + className="ark-message-video absolute inset-0 h-full w-full" /> - ) : ( <> @@ -109,6 +99,8 @@ function VideoAttachmentCard({ ) : (