vue3 图片/视频 加载失败重试
需求背景
用户手机上传图片走
oss
,在pc端在线客服连接socket
需要实时推送消息,接受到消息后,由于oss还回没有回调成功
,所以图片/视频不能及时展示
,所以做了一个失败重试
的功能
效果图
技术方案
- 服务端接收到
oss
的回调,再给客户端发送一条消息,告诉回调成功了,但是前端存在一定滞后性 - 前端通过媒体组件提供的
error
事件,做回调监听,当前你可以一直监听,也可以做loadNumber次数限制
代码实现
<!-- 媒体组件 可以用于聊天气泡/工单媒体数据展示 -->
<template>
<div v-if="!pathIsMp4(props.msg)" :style="{ width: props.width + 'px', height: props.height + 'px' }">
<el-image
v-if="isLoaded"
:src="imgUrl.src"
fit="cover"
:preview-src-list="[imgUrl.src]"
:zoom-rate="1.2"
:max-scale="7"
:min-scale="0.5"
lazy
>
<template #error>
<div>{{ $t('common_loading_error') }}</div>
</template>
</el-image>
<div v-else >{{ $t('common_loading') }}...</div>
</div>
<div v-else :style="{ width: props.width + 'px', height: props.height + 'px' }">
<video ref="videoRefs" controls :src="imgUrl.src" @error="handleError">
Your browser does not support the video tag.
</video>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
import { pathIsMp4 } from 'mt-core-lib'
const props = defineProps({
msg: {
type: String,
required: true,
default: ''
},
width: {
type: String,
default: '138'
},
height: {
type: String,
default: '184'
}
})
const imgUrl = reactive({ src: props.msg })
const conversionImg = new Image()
const isLoaded = ref(false) // 加载状态标志
const loadNumber = ref(5) // 加载次数
const videoRefs = ref()
let retryTimer: ReturnType<typeof setTimeout>
const checkImageLoaded = () => {
const loadImg = () => {
conversionImg.onload = () => {
if (!isLoaded.value) {
isLoaded.value = true
imgUrl.src = conversionImg.src
clearTimeout(retryTimer) // 清除定时器
}
}
conversionImg.onerror = () => {
console.log('图片错误')
if (!isLoaded.value && loadNumber.value > 0) {
loadNumber.value--
retryTimer = setTimeout(loadImg, 2000) // 启动定时器
console.log('图片加载失败,重新加载', retryTimer)
} else {
isLoaded.value = true
clearTimeout(retryTimer) // 清除定时器
}
}
conversionImg.src = props.msg
}
// 使用 requestIdleCallback() 方法在浏览器空闲时执行 loadImg() 函数
if (window.requestIdleCallback) {
window.requestIdleCallback(() => {
loadImg()
})
} else {
setTimeout(loadImg, 0)
}
}
const handleError = (event: Event) => {
console.log('视频加载失败', event)
// 使用 requestIdleCallback() 方法在浏览器空闲时执行 load() 函数
if (window.requestIdleCallback) {
window.requestIdleCallback(() => {
videoRefs.value.load()
})
} else {
setTimeout(() => {
videoRefs.value.load()
}, 1000)
}
}
onMounted(() => {
if (!pathIsMp4(props.msg)) {
checkImageLoaded()
}
})
onBeforeUnmount(() => {
clearTimeout(retryTimer) // 清除定时器
})
</script>
总结
- 媒体组件,提供了失败的回调,可以使用
失败回调
,不断的load来加载数据 - 加载成功后,或者到达一定次数时,注意及时
销毁