VideoBackground.vue 3.94 KB
<!--
 * @Date: 2025-12-26 14:15:46
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-12-31 16:47:19
 * @FilePath: /mlaj/src/components/ui/VideoBackground.vue
 * @Description: 文件描述
-->
<template>
    <div class="video-background fixed inset-0 -z-10 overflow-hidden">
        <video v-show="!use_image_bg" ref="videoPlayer" autoplay muted loop playsinline webkit-playsinline
            preload="auto" @error="on_video_error" @stalled="on_video_error" @abort="on_video_error"
            @emptied="on_video_error" @loadeddata="on_video_loaded" class="w-full h-full object-cover">
            <source :src="videoUrl" type="video/mp4" />
            Your browser does not support the video tag.
        </video>

        <!-- 图片降级背景(视频不可用时显示) -->
        <div v-if="use_image_bg" class="w-full h-full bg-cover bg-center bg-no-repeat"
            :style="{ backgroundImage: `url(${backgroundImage})` }">
        </div>

        <!-- 遮罩层,确保内容可读性 -->
        <div class="absolute inset-0 bg-black/10"></div>
    </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
/**
 * 视频背景组件
 * @description 循环播放指定的视频作为背景
 */
const props = defineProps({
    videoUrl: {
        type: String,
        // default: 'https://cdn.ipadbiz.cn/mlaj/recall/video/%E5%AE%87%E5%AE%99-1.mp4'
        default: 'https://cdn.ipadbiz.cn/mlaj/recall/video/u8yvl6rs7q.mp4'
    },
    backgroundImage: {
        type: String,
        // default: 'https://cdn.ipadbiz.cn/mlaj/recall/video/%E5%AE%87%E5%AE%99-2.png'
        default: 'https://cdn.ipadbiz.cn/mlaj/recall/img/i3a85rdk.png'
    }
})

const videoPlayer = ref(null)
const use_image_bg = ref(false)
const is_video_ready = ref(false)

onMounted(() => {
    const video = videoPlayer.value
    if (video) {
        // 尝试播放视频
        const playPromise = video.play()

        if (playPromise !== undefined) {
            playPromise.catch(error => {
                // 自动播放被阻止:在微信环境下尝试通过 WeixinJSBridge 播放
                // 说明:避免控制台输出引起诊断问题
                void error
                const ua = navigator.userAgent.toLowerCase()
                if (ua.match(/MicroMessenger/i) && typeof window.WeixinJSBridge !== 'undefined') {
                    window.WeixinJSBridge.invoke('getNetworkType', {}, () => {
                        video.play()
                    })
                }
                // 若短时间内仍无法播放,降级为图片背景,避免黑屏
                setTimeout(() => {
                    if (!is_video_ready.value) {
                        enable_image_fallback()
                    }
                }, 1200)
            })
        }

        // 监听微信JSBridgeReady事件
        document.addEventListener('WeixinJSBridgeReady', () => {
            video.play()
        }, false)
    }

    // 兜底:在一定时间内仍未加载完成则切换到图片背景
    setTimeout(() => {
        if (!is_video_ready.value) {
            enable_image_fallback()
        }
    }, 5000)
})

/**
 * 视频加载成功回调
 * 说明:标记视频已可播放,用于取消降级处理
 */
const on_video_loaded = () => {
    is_video_ready.value = true
}

/**
 * 视频错误回调
 * 说明:视频加载/播放失败时触发图片降级,避免黑屏
 * @param {Event} e 事件对象
 */
const on_video_error = (e) => {
    void e
    enable_image_fallback()
}

/**
 * 启用图片降级背景
 * 说明:切换到全屏图片背景,保证用户视觉不出现黑屏
 */
const enable_image_fallback = () => {
    use_image_bg.value = true
}
</script>

<style scoped>
.video-background {
    /* 确保在所有内容之下 */
    z-index: -1;
    top: -1px;
    right: -1px;
    bottom: -1px;
    left: -1px;
    background-image: url(https://cdn.ipadbiz.cn/mlaj/recall/img/bg01@2x.png?imageMogr2/thumbnail/400x/strip/quality/50);
}
</style>