@@ -758,6 +759,7 @@ import Forwarder from "./Forwarder/index.vue";
import {throttle} from "lodash";
import transformEmojiToHtml from "../../../utils/emoji";
import {webhookEventOptions} from "../../../utils/webhook";
+import {imageFailedSrc, markImageFailed, unmarkImageFailed} from "../../../utils/imageFailed";
export default {
name: "DialogWrapper",
@@ -2515,6 +2517,20 @@ export default {
}
},
+ // 图片加载失败后换成占位图并登记,消息重新渲染时不再请求(Safari 不缓存失败图片,会反复请求)
+ onImageError({target}) {
+ if (target.tagName !== 'IMG' || target.dataset.failedSrc !== undefined) {
+ return
+ }
+ const src = target.getAttribute('src')
+ if (!src || src.startsWith('data:')) {
+ return
+ }
+ markImageFailed(src)
+ target.dataset.failedSrc = src
+ target.src = imageFailedSrc
+ },
+
onPointerover({pointerType}) {
this.pointerMouse = pointerType === 'mouse';
},
@@ -3936,6 +3952,13 @@ export default {
switch (target.nodeName) {
// 打开图片
case "IMG":
+ // 加载失败的图片点击重试
+ if (target.dataset.failedSrc !== undefined) {
+ unmarkImageFailed(target.dataset.failedSrc)
+ target.src = target.dataset.failedSrc
+ delete target.dataset.failedSrc
+ break
+ }
if (!(target.classList.contains('browse') && this.onViewPicture(target.currentSrc))) {
const list = $A.getTextImagesInfo(el.outerHTML)
this.$store.dispatch("previewImage", {index: target.currentSrc, list})
diff --git a/resources/assets/js/utils/imageFailed.js b/resources/assets/js/utils/imageFailed.js
new file mode 100644
index 000000000..e495e9399
--- /dev/null
+++ b/resources/assets/js/utils/imageFailed.js
@@ -0,0 +1,28 @@
+/**
+ * 消息内加载失败的图片登记
+ *
+ * Safari 不缓存失败(如 404)的图片,虚拟列表回收/重挂载消息时 v-html 会重建
![]()
,
+ * 导致反复请求;且失败图片尺寸塌陷又会触发列表重新测量,形成循环。
+ * 这里按地址记住失败的图片,重新渲染时直接输出占位图,不再请求。
+ */
+
+// 透明 1x1 gif,失败样式由 img[data-failed-src] 提供
+export const imageFailedSrc = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
+
+const failedSet = new Set()
+
+const normalize = src => `${src || ''}`.replace(/&/g, '&')
+
+export function markImageFailed(src) {
+ if (src && !src.startsWith('data:')) {
+ failedSet.add(normalize(src))
+ }
+}
+
+export function unmarkImageFailed(src) {
+ failedSet.delete(normalize(src))
+}
+
+export function isImageFailed(src) {
+ return failedSet.size > 0 && failedSet.has(normalize(src))
+}
diff --git a/resources/assets/sass/pages/components/dialog-wrapper.scss b/resources/assets/sass/pages/components/dialog-wrapper.scss
index 666eda3ef..c29c06940 100644
--- a/resources/assets/sass/pages/components/dialog-wrapper.scss
+++ b/resources/assets/sass/pages/components/dialog-wrapper.scss
@@ -585,6 +585,13 @@
-webkit-overflow-scrolling: touch;
}
+ img[data-failed-src] {
+ min-width: 36px;
+ min-height: 36px;
+ background: rgba(0, 0, 0, 0.06) url("data:image/svg+xml,%3Csvg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M510.496 708.16H256.448c-25.504 0-46.176-18.032-46.176-40.288v-31.12l136.096-102.688 48.784 41.92c25.36 21.92 65.68 23.36 93.008 3.344l230.048-169.68 92.464 80.8c9.312 8.72 13.232 12.656 23.456 12.656 7.344 0 13.44-3.6 18.096-8.64 4.96-5.376 4.64-18.272 4.64-24.672V264.864c0-44.512-41.36-80.592-92.368-80.592H256.448c-51.008 0-92.368 36.08-92.368 80.592v403.008c0 21.376 9.728 41.888 27.056 56.992 17.328 15.104 40.816 23.616 65.312 23.616h253.568c11.808 0 22.656-8.368 23.504-18.656 0.96-11.808-9.712-21.632-22.992-21.632l-0.032-0.016zM210.272 264.88c0-22.24 20.672-40.288 46.176-40.288H764.48c25.504 0 46.176 18.032 46.192 40.288v168.656l-61.248-53.536c-17.12-12.64-42.176-12.688-59.36-0.112l-231.552 168.48c-9.12 6.608-22.48 6.144-30.912-1.088l-48.832-41.92c-17.2-14.624-44.384-15.392-62.624-1.76l-105.872 79.936V264.864z m120.752 94.48c0 11.952 3.568 23.648 10.256 33.584a60.8 60.8 0 0 0 27.328 22.272 61.264 61.264 0 0 0 66.336-13.104 60.064 60.064 0 0 0 13.2-65.888 60.544 60.544 0 0 0-22.416-27.12 61.184 61.184 0 0 0-76.88 7.52 60.416 60.416 0 0 0-17.824 42.72z m524.832 228.96a140.32 140.32 0 0 1 0 199.456c-55.504 55.088-145.408 55.12-200.88 0a140.544 140.544 0 0 1-40.72-99.488 140.56 140.56 0 0 1 41.6-99.12 142.56 142.56 0 0 1 99.824-41.312 142.56 142.56 0 0 1 100.16 40.448zM683.664 759.264a102.032 102.032 0 0 0 127.632 12.816l-140.544-139.616a100.224 100.224 0 0 0 12.912 126.752v0.048z m156.368-15.76a100.224 100.224 0 0 0-13.024-126.64 102.032 102.032 0 0 0-127.52-12.928l140.544 139.568z' fill='%23D9D9D9'%3E%3C/path%3E%3C/svg%3E") center / 36px no-repeat;
+ cursor: pointer;
+ }
+
.item-leave {
pre,
code,