垃圾堆中的精品

垃圾堆中的精品

UNIAPP 实现H5+APP播放透明背景视频

业务遇到有个APP需要播放透明背景视频,穿插到AI生成的音频中,还要监听播放完成等事件。废话不多说直接上代码

<template>
	<view class="sp-class" v-html="videoHtml" ref="videoContainer"></view>
</template>

<script>
export default {
    data() {
        return {
            videoUrl: 'https://cdn.itnan.ren/demo5.webm',
            videoElement: null // 存储视频元素的引用
        }
    },
    computed: {
        videoHtml() {
            return` <video width = "300"
            height = "300"
            style = "width: 100%;height: 100%;z-index: 10080 !important; background: transparent !important;"
            src = "${this.videoUrl}"
            class = "transparent-video"
            autoplay muted preload = "auto" / > `
        }
    },
    mounted() {
        this.$nextTick(() = > {
            this.bindVideoEvents();
        });
    },
    methods: {
        bindVideoEvents() {
            try {
                // 方法1: 尝试直接通过 ref 获取
                let container = this.$refs.videoContainer;
                // 如果 ref 是一个 Vue 组件实例,尝试获取其 $el
                if (container && container.$el) {
                    container = container.$el;
                }
                // 如果 ref 是数组(在某些情况下可能发生)
                if (Array.isArray(container)) {
                    container = container[0];
                    if (container && container.$el) {
                        container = container.$el;
                    }
                }
                console.log('Container type:', typeof container, container);
                if (container && container.querySelector) {
                    const videoElement = container.querySelector('.transparent-video');
                    if (videoElement) {
                        this.videoElement = videoElement;
                        this.setupTransparentVideo(videoElement);
                        this.addVideoEventListeners(videoElement);
                    } else {
                        console.warn('未找到 video 元素,延迟重试...');
                        setTimeout(() = > this.bindVideoEvents(), 100);
                    }
                } else {
                    console.warn('容器不可用,延迟重试...');
                    setTimeout(() = > this.bindVideoEvents(), 100);
                }
            } catch (error) {
                console.error('绑定视频事件时出错:', error);
                // 延迟重试
                setTimeout(() = > this.bindVideoEvents(), 100);
            }
        },
        addVideoEventListeners(videoElement) {
            // 移除可能已存在的事件监听器
            this.removeVideoEventListeners(videoElement);
            // 添加新的事件监听器
            videoElement.addEventListener('ended', this.handleVideoEnded);
            videoElement.addEventListener('error', this.handleVideoError);
            videoElement.addEventListener('loadeddata', this.onVideoLoaded);
            videoElement.addEventListener('canplay', this.onVideoCanPlay);
        },
        removeVideoEventListeners(videoElement) {
            if (videoElement) {
                videoElement.removeEventListener('ended', this.handleVideoEnded);
                videoElement.removeEventListener('error', this.handleVideoError);
                videoElement.removeEventListener('loadeddata', this.onVideoLoaded);
                videoElement.removeEventListener('canplay', this.onVideoCanPlay);
            }
        },
        setupTransparentVideo(videoElement) {
            // 设置透明背景相关属性
            videoElement.style.background = 'transparent';
            videoElement.style.backgroundColor = 'transparent';
            // 设置必要的属性
            videoElement.setAttribute('playsinline', 'true');
            videoElement.setAttribute('webkit-playsinline', 'true');
            videoElement.setAttribute('preload', 'auto');
            // 对于透明视频的特殊处理
            videoElement.style.mixBlendMode = 'screen';
        },
        onVideoLoaded() {
            console.log('透明视频加载完成');
        },
        onVideoCanPlay() {
            console.log('透明视频可以播放');
        },
        handleVideoEnded() {
            console.log('透明视频播放完成');
            // 播放完成后的处理逻辑
            this.$emit('video-ended');
            // 可以在这里添加重新播放或其他逻辑
            // this.restartVideo();
        },
        handleVideoError(e) {
            console.error('透明视频播放错误:', e);
            if (e.target && e.target.error) {
                console.error('错误详情:', e.target.error);
            }
        },
        // 重新播放方法
        restartVideo() {
            if (this.videoElement) {
                this.videoElement.currentTime = 0;
                this.videoElement.play().
                catch (error = > {
                    console.error('重新播放失败:', error);
                });
            }
        },
        // 手动播放控制方法
        playVideo() {
            if (this.videoElement) {
                this.videoElement.play().
                catch (error = > {
                    console.error('播放失败:', error);
                });
            }
        },
        pauseVideo() {
            if (this.videoElement) {
                this.videoElement.pause();
            }
        }
    },
    beforeDestroy() {
        // 清理事件监听
        if (this.videoElement) {
            this.removeVideoEventListeners(this.videoElement);
        }
    },
    watch: {
        // 如果 videoUrl 发生变化,重新绑定事件
        videoUrl() {
            this.$nextTick(() = > {
                setTimeout(() = > this.bindVideoEvents(), 200);
            });
        }
    }
}
</script>

<style scoped>
.sp-class {
	position: fixed;
	left: 0;
	top: 0;
	width: 750rpx;
	height: 100vh;
	z-index: 10080 !important;
	// border: 1rpx solid red;
}
.transparent-video::cue {
	display: none;
}

.transparent-video::-webkit-media-controls-panel {
	background-color: transparent;
}
</style>
Vue

运行即可。但是需注意播放的视频需要透明才能看到结果。需合成透明底色movg格式视频(AE、PR、剪映SVIP 等专业软件),然后用ffmpeg转为webm即可

评论回复

回到顶部