|
30 | 30 | </div> |
31 | 31 | <div v-else-if="message.renderType === 'image'" |
32 | 32 | class="max-w-sm"> |
33 | | - <div class="msg-radius overflow-hidden cursor-pointer" :class="message.isSent ? '' : ''" @click="message.imageUrl && openImagePreview(message.imageUrl)" @contextmenu="openMediaContextMenu($event, message, 'image')"> |
34 | | - <img v-if="message.imageUrl" :src="message.imageUrl" alt="图片" class="max-w-[240px] max-h-[240px] object-cover hover:opacity-90 transition-opacity"> |
| 33 | + <div class="msg-radius overflow-hidden cursor-pointer" :class="message.isSent ? '' : ''" @click="message.imageUrl && openImagePreview(message.imageUrl)" @contextmenu="openMediaContextMenu($event, message, 'image')"> |
| 34 | + <img |
| 35 | + v-if="message.imageUrl" |
| 36 | + v-chat-lazy-src="message.imageUrl" |
| 37 | + alt="图片" |
| 38 | + class="block min-w-[96px] min-h-[96px] max-w-[240px] max-h-[240px] object-cover bg-gray-100 hover:opacity-90 transition-opacity" |
| 39 | + loading="lazy" |
| 40 | + decoding="async" |
| 41 | + fetchpriority="low" |
| 42 | + v-chat-media-perf="{ kind: 'message-image', meta: { conversation: selectedContact?.username || '', messageId: message.id, serverId: message.serverIdStr || '', imageMd5: message.imageMd5 || '', imageFileId: message.imageFileId || '' } }" |
| 43 | + > |
35 | 44 | <div v-else class="px-3 py-2 text-sm max-w-sm relative msg-bubble whitespace-pre-wrap break-words leading-relaxed" |
36 | 45 | :class="message.isSent ? 'bg-[#95EC69] text-black bubble-tail-r' : 'bg-white text-gray-800 bubble-tail-l'"> |
37 | 46 | {{ message.content }} |
|
40 | 49 | </div> |
41 | 50 | <div v-else-if="message.renderType === 'video'" class="max-w-sm"> |
42 | 51 | <div class="msg-radius overflow-hidden relative bg-black/5" @contextmenu="openMediaContextMenu($event, message, 'video')"> |
43 | | - <img v-if="message.videoThumbUrl" :src="message.videoThumbUrl" alt="视频" class="block w-[220px] max-w-[260px] h-auto max-h-[260px] object-cover"> |
| 52 | + <img |
| 53 | + v-if="message.videoThumbUrl" |
| 54 | + v-chat-lazy-src="message.videoThumbUrl" |
| 55 | + alt="视频" |
| 56 | + class="block w-[220px] min-h-[120px] max-w-[260px] h-auto max-h-[260px] object-cover bg-gray-100" |
| 57 | + loading="lazy" |
| 58 | + decoding="async" |
| 59 | + fetchpriority="low" |
| 60 | + v-chat-media-perf="{ kind: 'message-video-thumb', meta: { conversation: selectedContact?.username || '', messageId: message.id, serverId: message.serverIdStr || '', videoThumbMd5: message.videoThumbMd5 || '', videoThumbFileId: message.videoThumbFileId || '' } }" |
| 61 | + > |
44 | 62 | <div v-else class="px-3 py-2 text-sm relative msg-bubble whitespace-pre-wrap break-words leading-relaxed" |
45 | 63 | :class="message.isSent ? 'bg-[#95EC69] text-black bubble-tail-r' : 'bg-white text-gray-800 bubble-tail-l'"> |
46 | 64 | {{ message.content }} |
|
100 | 118 | </div> |
101 | 119 | <div v-else-if="message.renderType === 'emoji'" class="max-w-sm flex items-center group" :class="message.isSent ? 'flex-row-reverse' : ''"> |
102 | 120 | <template v-if="message.emojiUrl"> |
103 | | - <img :src="message.emojiUrl" alt="表情" class="w-24 h-24 object-contain" @contextmenu="openMediaContextMenu($event, message, 'emoji')"> |
| 121 | + <img |
| 122 | + v-chat-lazy-src="message.emojiUrl" |
| 123 | + alt="表情" |
| 124 | + class="w-24 h-24 object-contain" |
| 125 | + loading="lazy" |
| 126 | + decoding="async" |
| 127 | + fetchpriority="low" |
| 128 | + @contextmenu="openMediaContextMenu($event, message, 'emoji')" |
| 129 | + > |
104 | 130 | <button |
105 | 131 | v-if="shouldShowEmojiDownload(message)" |
106 | 132 | class="text-xs px-2 py-1 rounded bg-white border border-gray-200 text-gray-700 opacity-0 group-hover:opacity-100 transition-opacity" |
|
122 | 148 | :class="message.isSent ? 'bg-[#95EC69] text-black bubble-tail-r' : 'bg-white text-gray-800 bubble-tail-l'"> |
123 | 149 | <span v-for="(seg, idx) in parseTextWithEmoji(message.content)" :key="idx"> |
124 | 150 | <span v-if="seg.type === 'text'">{{ seg.content }}</span> |
125 | | - <img v-else :src="seg.emojiSrc" :alt="seg.content" class="inline-block w-[1.25em] h-[1.25em] align-text-bottom mx-px"> |
| 151 | + <img v-else :src="seg.emojiSrc" :alt="seg.content" class="inline-block w-[1.25em] h-[1.25em] align-text-bottom mx-px" loading="lazy" decoding="async"> |
126 | 152 | </span> |
127 | 153 | </div> |
128 | 154 | <div |
|
189 | 215 | class="ml-2 my-2 flex-shrink-0 max-w-[98px] max-h-[49px] overflow-hidden flex items-center justify-center cursor-pointer" |
190 | 216 | @click.stop="openImagePreview(message.quoteThumbUrl)" |
191 | 217 | > |
192 | | - <img |
193 | | - :src="message.quoteThumbUrl" |
194 | | - alt="引用链接缩略图" |
195 | | - class="max-h-[49px] w-auto max-w-[98px] object-contain" |
196 | | - loading="lazy" |
197 | | - decoding="async" |
198 | | - referrerpolicy="no-referrer" |
| 218 | + <img |
| 219 | + v-chat-lazy-src="message.quoteThumbUrl" |
| 220 | + alt="引用链接缩略图" |
| 221 | + class="max-h-[49px] w-auto max-w-[98px] object-contain" |
| 222 | + loading="lazy" |
| 223 | + decoding="async" |
| 224 | + fetchpriority="low" |
| 225 | + referrerpolicy="no-referrer" |
| 226 | + v-chat-media-perf="{ kind: 'quote-thumb', meta: { conversation: selectedContact?.username || '', messageId: message.id, quoteServerId: message.quoteServerId || '' } }" |
199 | 227 | @error="onQuoteThumbError(message)" |
200 | 228 | /> |
201 | 229 | </div> |
|
204 | 232 | class="ml-2 my-2 flex-shrink-0 max-w-[98px] max-h-[49px] overflow-hidden flex items-center justify-center cursor-pointer" |
205 | 233 | @click.stop="openImagePreview(message.quoteImageUrl)" |
206 | 234 | > |
207 | | - <img |
208 | | - :src="message.quoteImageUrl" |
209 | | - alt="引用图片" |
210 | | - class="max-h-[49px] w-auto max-w-[98px] object-contain" |
211 | | - loading="lazy" |
212 | | - decoding="async" |
| 235 | + <img |
| 236 | + v-chat-lazy-src="message.quoteImageUrl" |
| 237 | + alt="引用图片" |
| 238 | + class="max-h-[49px] w-auto max-w-[98px] object-contain" |
| 239 | + loading="lazy" |
| 240 | + decoding="async" |
| 241 | + fetchpriority="low" |
| 242 | + v-chat-media-perf="{ kind: 'quote-image', meta: { conversation: selectedContact?.username || '', messageId: message.id, quoteServerId: message.quoteServerId || '' } }" |
213 | 243 | @error="onQuoteImageError(message)" |
214 | 244 | /> |
215 | 245 | </div> |
|
0 commit comments