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-imagev-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 = trueimgUrl.src = conversionImg.srcclearTimeout(retryTimer) // 清除定时器}}conversionImg.onerror = () => {console.log('图片错误')if (!isLoaded.value && loadNumber.value > 0) {loadNumber.value--retryTimer = setTimeout(loadImg, 2000) // 启动定时器console.log('图片加载失败,重新加载', retryTimer)} else {isLoaded.value = trueclearTimeout(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来加载数据 - 加载成功后,或者到达一定次数时,注意及时
销毁