mirror of
https://github.com/kuaifan/dootask.git
synced 2026-10-29 22:10:42 +00:00
fix(dialog): Safari 中加载失败的消息图片滚动时不再反复请求
- 失败图片按地址登记,消息回收重挂载时直接渲染占位图,不再请求 - 文本消息图片改为 inline-block,失败后保持原占位尺寸,避免高度塌陷触发列表反复测量 - 失败占位图点击可重试加载
This commit is contained in:
parent
cb35aaca2b
commit
a1e79204f8
10
resources/assets/js/functions/web.js
vendored
10
resources/assets/js/functions/web.js
vendored
@ -1,11 +1,15 @@
|
||||
import {MarkdownPreview} from "../utils/markdown";
|
||||
import {convertLocalResourcePath} from "../components/Replace/utils";
|
||||
import {imageFailedSrc, isImageFailed} from "../utils/imageFailed";
|
||||
|
||||
/**
|
||||
* 页面专用
|
||||
*/
|
||||
(function (window) {
|
||||
const $ = window.$A;
|
||||
|
||||
// 已加载失败的图片直接输出占位图,避免重新渲染时反复请求
|
||||
const imageSrcAttr = src => isImageFailed(src) ? `src="${imageFailedSrc}" data-failed-src="${src}"` : `src="${src}"`;
|
||||
/**
|
||||
* =============================================================================
|
||||
* ******************************* web extra *******************************
|
||||
@ -405,10 +409,12 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
|
||||
const value = item.original
|
||||
.replace(/\s+width=/, ` original-width=`)
|
||||
.replace(/\s+height=/, ` original-height=`)
|
||||
.replace(/\s+src=(["'])([^'"]*)\1/i, ` style="width:${data.width}px;height:${data.height}px" src="${convertLocalResourcePath(data.src)}"`)
|
||||
.replace(/\s+src=(["'])([^'"]*)\1/i, ` style="width:${data.width}px;height:${data.height}px" ${imageSrcAttr(convertLocalResourcePath(data.src))}`)
|
||||
text = text.replace(item.original, value)
|
||||
} else {
|
||||
text = text.replace(item.original, `<div class="no-size-image-box">${item.original}</div>`);
|
||||
const value = item.original
|
||||
.replace(/\s+src=(["'])([^'"]*)\1/i, (match, quote, src) => ` ${imageSrcAttr(src)}`)
|
||||
text = text.replace(item.original, `<div class="no-size-image-box">${value}</div>`);
|
||||
}
|
||||
})
|
||||
return text;
|
||||
|
||||
@ -181,7 +181,8 @@
|
||||
<div
|
||||
ref="msgs"
|
||||
class="dialog-msgs"
|
||||
v-longpress="{callback: handleLongpress, preventEndEvent: true}">
|
||||
v-longpress="{callback: handleLongpress, preventEndEvent: true}"
|
||||
@error.capture="onImageError">
|
||||
<!--定位提示-->
|
||||
<div v-if="positionShow && positionMsg" class="dialog-position">
|
||||
<div class="position-label" @click="onPositionMark(positionMsg.msg_id)">
|
||||
@ -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})
|
||||
|
||||
28
resources/assets/js/utils/imageFailed.js
vendored
Normal file
28
resources/assets/js/utils/imageFailed.js
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 消息内加载失败的图片登记
|
||||
*
|
||||
* Safari 不缓存失败(如 404)的图片,虚拟列表回收/重挂载消息时 v-html 会重建 <img>,
|
||||
* 导致反复请求;且失败图片尺寸塌陷又会触发列表重新测量,形成循环。
|
||||
* 这里按地址记住失败的图片,重新渲染时直接输出占位图,不再请求。
|
||||
*/
|
||||
|
||||
// 透明 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))
|
||||
}
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user